Οι μηχανισμοί χρονοδιακόπτη σάς επιτρέπουν να προγραμματίζετε τον πυρήνα του λειτουργικού συστήματος να ειδοποιεί μια εφαρμογή όταν παρέλθει ένας προκαθορισμένος χρόνος. Συνήθως θα τα χρησιμοποιείτε παρέχοντας δύο πληροφορίες. Αρχικά, θα πρέπει να καθορίσετε πόσο χρόνο θα χρειαστεί ο χρονοδιακόπτης πριν από την ειδοποίηση. Δεύτερον, θα πρέπει να προετοιμάσετε μια λειτουργία επανάκλησης για να ενεργήσετε όταν εμφανιστεί αυτή η ειδοποίηση.
Παραδοσιακή προσέγγιση στα χρονόμετρα
Οι μηχανισμοί χρονοδιακόπτη σε συστήματα που βασίζονται σε Linux και Unix έχουν εξελιχθεί για να εξυπηρετούν διάφορες ανάγκες. Διαφορετικές προσεγγίσεις μπορούν να σας βοηθήσουν να λύσετε διαφορετικούς τύπους προβλημάτων. Ωστόσο, θα βλέπετε συχνά την πρώτη έκδοση του τρομάζω() μηχανισμός που χρησιμοποιείται ακόμα.
Η λειτουργία συναγερμού είναι ο απλούστερος τρόπος χρήσης ενός χρονοδιακόπτη. ορίστε το πρωτότυπο του:
ανυπόγραφοενθτρομάζω(ανυπόγραφοενθ δευτερόλεπτα);
Χρησιμοποιώντας αυτήν τη μέθοδο, μπορείτε να καθορίσετε την ώρα μόνο σε ολόκληρα δευτερόλεπτα. Όταν τελειώσει ο χρόνος, το λειτουργικό σύστημα στέλνει το
SIGALRM σήμα στην αίτησή σας. Για να επεξεργαστείτε τη λήξη του χρονοδιακόπτη στην εφαρμογή σας, θα πρέπει επίσης να ορίσετε μια λειτουργία επανάκλησης.Ακολουθεί ένα παράδειγμα λειτουργίας χειριστή σήματος:
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνωκενόςtimer_callback(ενθ signum)
{
time_t τώρα = ώρα(ΜΗΔΕΝΙΚΟ);
printf("Σήμα %d πιάστηκε στο %li", signum, τώρα);
}
ενθκύριος()
{
σήμα (SIGALRM, timer_callback);
τρομάζω(1);
ύπνος(3);
ΕΠΙΣΤΡΟΦΗ0;
}
Αυτός ο κώδικας εγείρει ένα SIGALRM σήμα μετά 1 δεύτερος. Εάν θέλετε να αυξήσετε την καθυστέρηση του χρονοδιακόπτη σε πέντε δευτερόλεπτα, απλώς καλέστε συναγερμός (5) αντι αυτου. Για να σταματήσετε το χρονόμετρο, περάστε μια τιμή 0: συναγερμός (0).
Όταν τελειώσει ο χρόνος, ο χρονοδιακόπτης που χρησιμοποιείτε δεν θα επανεκκινείται περιοδικά. Για παράδειγμα, εάν θέλετε να καθυστερήσετε για άλλο ένα δευτερόλεπτο, θα πρέπει να επανεκκινήσετε τον μηχανισμό με μια άλλη κλήση προς τρομάζω().
Παρά την ευκολία χρήσης της, αυτή η μέθοδος έχει ορισμένα μειονεκτήματα:
- Μόνο ένα χρονόμετρο τη φορά.
- Δεν υπάρχει υποστήριξη περιοδικού χρονοδιακόπτη.
- Μπορείτε να δώσετε τη χρονική περίοδο μόνο σε πολλαπλάσια ολόκληρων δευτερολέπτων.
- Δεν υπάρχει τρόπος να γνωρίζουμε πόσος χρόνος απομένει σε ένα χρονόμετρο.
Αποθηκεύστε το δείγμα κώδικα που δίνεται παραπάνω ως συναγερμός.γ. Πότε μεταγλωττίζεις και τρέχεις αυτό, το πρόγραμμα θα καλέσει το timer_callback λειτουργία μετά από ένα δευτερόλεπτο. Στη συνέχεια θα περιμένει για τα υπόλοιπα δύο δευτερόλεπτα λόγω του ύπνος (3) γραμμή και μετά τερματίστε.
$ gcc -o συναγερμός.γ
$ χρόνος ./συναγερμός
Το σήμα 14 πιάστηκε στο 1653490465
πραγματικό 0m1.004s
χρήστη 0m0.000s
sys 0m0.003s
Ο λόγος για τη χρήση της εντολής time είναι για να μπορείτε να δείτε τους χρόνους. Αλλά αν κοιτάξετε το αποτέλεσμα, ο συνολικός χρόνος λειτουργίας δεν είναι τρία δευτερόλεπτα. Αυτό οφείλεται στο SIGALRM σήμα από συναγερμός (1) όταν τελειώσει το πρώτο δευτερόλεπτο, ενώ το syscall που προκαλείται από τη λειτουργία ύπνου (3). Όταν φτάσει αυτό το σήμα, διακόπτει το syscall που έχει ξεκινήσει για ύπνος (3).
Χρήση χρονοδιακόπτη διαστήματος
Ο μηχανισμός χρονοδιακόπτη διαστήματος ήταν αρχικά διαθέσιμος στην έκδοση 4.2 BSD. Ήταν αργότερα τυποποιημένο από το POSIX. Τα κύρια πλεονεκτήματά του έναντι του παραδοσιακού τρομάζω() Η βασισμένη μέθοδος χρονοδιακόπτη είναι:
- Παρέχει ανάλυση μικροδευτερολέπτων.
- Επιτρέπει τον έλεγχο της μέτρησης του χρόνου με περισσότερες λεπτομέρειες σε τρεις διαφορετικούς τρόπους λειτουργίας.
- Είναι δυνατό να το ρυθμίσετε μία φορά και να το κάνετε να λειτουργεί περιοδικά.
- Είναι δυνατό να μάθετε πόσο καιρό είναι παρόν σε κάθε δεδομένη στιγμή.
Τα πρωτότυπα λειτουργιών που χρησιμοποιούνται για λειτουργίες χρονοδιακόπτη διαστήματος είναι τα εξής:
#περιλαμβάνω
ενθρυθμιστής(ενθ οι οποίες, συνθ struct itimerval *newValue, struct itimerval *oldValue);
ενθgettimer(ενθ που, struct itimerval *value);structχρονοδιάγραμμα
{
structχρονικό διάστημαitInδιάστημα;// επόμενη τιμή
structχρονικό διάστημαitValue;// τρέχουσα τιμή
};
structχρονικό διάστημα
{
μακρύς tv_sec;
μακρύς tv_usec;
};
Εάν θέλετε να ρυθμίσετε ένα χρονόμετρο διαστήματος, θα πρέπει να χρησιμοποιήσετε το χρονοδιάγραμμα struct. Θα χρειαστεί να περάσετε μια τιμή χρησιμοποιώντας αυτήν τη δομή ως δεύτερο όρισμα στο ρυθμιστής λειτουργία.
Για παράδειγμα, ένας χρονοδιακόπτης διαστήματος που θα ειδοποιεί την αίτησή σας για 1 δευτερόλεπτο και μετά κάθε 300 χιλιοστά του δευτερολέπτου μπορεί να ρυθμιστεί ως εξής:
structχρονοδιάγραμμαnewTimer;
structχρονοδιάγραμμαoldTimer;newTimer.itValue.tv_sec = 1;
newTimer.itValue.tv_usec = 0;newTimer.itInterval.tv_sec = 0;
newTimer.itInterval.tv_usec = 300 * 1000;
settimer (ITIMER_REAL, &newTimer, &oldTimer);
Εάν υπάρχει ενεργός χρονοδιακόπτης διαστήματος πριν οριστούν οι νέες τιμές, οι τιμές του μεταφέρονται στη μεταβλητή διεύθυνση του χρονοδιάγραμμα τύπος που δίνεται στην τρίτη παράμετρο της συνάρτησης.
Μπορείτε να ρυθμίσετε τρεις διαφορετικούς τύπους χρονόμετρων με το μηχανισμό χρονοδιακόπτη διαστήματος. Καθορίστε τον τύπο του χρονοδιακόπτη στην πρώτη παράμετρο του settimer():
Τύπος χρονοδιακόπτη | Σήμα | Εξήγηση |
---|---|---|
ITIMER_REAL | SIGALRM | Ανεξάρτητα από το χρόνο που αφιερώνει η εφαρμογή, υπολογίζεται επί του συνολικού χρόνου που έχει παρέλθει. |
ITIMER_VIRTUAL | SIGVTALRM | Υπολογίζεται κατά τη διάρκεια του χρόνου που η εφαρμογή εκτελείται μόνο σε λειτουργία χρήστη. |
ITIMER_PROF | ΣΙΓΠΡΟΦ | Υπολογίζεται πάνω από το άθροισμα του χρόνου που αφιερώνει η εφαρμογή τόσο σε λειτουργίες χρήστη όσο και σε λειτουργίες συστήματος. |
Μπορείτε να δείτε από αυτόν τον πίνακα ότι το ITIMER_REAL τύπος στέλνει α SIGALRM σήμα, ακριβώς όπως το τρομάζω() λειτουργία.
Χρήση χρονοδιακόπτη διαστήματος και τρομάζω() στην ίδια εφαρμογή θα είναι μπερδεμένο. Αν και μπορείτε να κάνετε δεύτερο έλεγχο για τον υπόλοιπο χρόνο με gettimer(), δεν έχει νόημα η ταυτόχρονη χρήση τους.
Ακολουθεί ένα παράδειγμα ορισμού της λειτουργίας χειριστή σήματος με το κεφαλίδα εντοπισμού σφαλμάτων:
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω "./debug.h"κενόςtimer_callback(ενθ signum)
{
structχρονικό διάστηματώρα;
gettimeofday (&τώρα, ΜΗΔΕΝΙΚΟ);
printf("Σήμα %d πιάστηκε στο %li.%03 λi ", signum, now.tv_sec, now.tv_usec / 1000);
}ενθκύριος()
{
ανυπόγραφοενθ εναπομείναν = 3;structχρονοδιάγραμμαnew_timer;
structχρονοδιάγραμμαold_timer;new_timer.it_value.tv_sec = 1;
new_timer.it_value.tv_usec = 0;
new_timer.it_interval.tv_sec = 0;
new_timer.it_interval.tv_usec = 300 * 1000;ρυθμιστής (ITIMER_REAL, &new_timer, &old_timer);
σήμα (SIGALRM, timer_callback);ενώ (κοιμήσου (υπόλοιπο) != 0)
{
αν (errno == EINTR)
debugf("sleep που διακόπτεται από σήμα");
αλλού
errorf("σφάλμα ύπνου %s", strerror (errno));
}
ΕΠΙΣΤΡΟΦΗ0;
}
Ο παραπάνω κώδικας χρησιμοποιεί το ύπνος() λειτουργία για αναμονή για τρία δευτερόλεπτα. Κατά τη διάρκεια αυτού του χρόνου, λειτουργεί ένας χρονοδιακόπτης διαστήματος, πρώτα για ένα δευτερόλεπτο και μετά σε διάστημα 300 χιλιοστών του δευτερολέπτου.
Για καλύτερη κατανόηση, αποθηκεύστε και μεταγλωττίστε το δείγμα κώδικα με το όνομα διάστημα.γ:
$ gcc -o διάστημα διαστήματος.γ
$ χρόνος ./διάστημα
Το σήμα 14 πιάστηκε στο 1653493614.325
εντοπισμός σφαλμάτων: ύπνος που διακόπτεται από σήμα (κύριο διάστημα.c: 36)
Το σήμα 14 πιάστηκε στο 1653493614.625
εντοπισμός σφαλμάτων: ύπνος που διακόπτεται από σήμα (κύριο διάστημα.c: 36)
Το σήμα 14 πιάστηκε στο 1653493614.925
εντοπισμός σφαλμάτων: ύπνος που διακόπτεται από σήμα (κύριο διάστημα.c: 36)
Το σήμα 14 έπιασε στο 1653493615.225
εντοπισμός σφαλμάτων: ύπνος που διακόπτεται από σήμα (κύριο διάστημα.c: 36)
Το σήμα 14 έπιασε στο 1653493615.525
...
Όπως μπορείτε να δείτε από την έξοδο μετά την εκτέλεση του χρονοδιακόπτη, καλεί τη λειτουργία επανάκλησης κάθε 300 χιλιοστά του δευτερολέπτου.
Ωστόσο, αφού περιμένετε λίγο ακόμα, θα παρατηρήσετε ότι η εφαρμογή δεν τερματίζεται. Συνεχίζει να εκτελεί τη λειτουργία επανάκλησης κάθε 300 χιλιοστά του δευτερολέπτου. Εάν αυξήσετε την τιμή του διαστήματος σε χιλιοστά του δευτερολέπτου, θα δείτε ότι η εφαρμογή τερματίζεται. Αυτό οφείλεται στην περιοχή χρήσης του ύπνος() λειτουργία.
Η σημασία της χρήσης χρονοδιακόπτη στο Linux
Ειδικά για εφαρμογές σε πραγματικό χρόνο, ο μηχανισμός του χρονοδιακόπτη έχει μεγάλη σημασία. Αυτή είναι επίσης μια λύση που χρησιμοποιείται για βελτιστοποιήσεις απόδοσης. Μπορείτε ακόμη να το χρησιμοποιήσετε για να μετρήσετε το χρόνο λειτουργίας ή την καθυστέρηση στην εφαρμογή σας. Είναι σημαντικό να χρησιμοποιείτε μηχανισμούς χρονοδιακόπτη για να παρακολουθείτε τον χρόνο που έχει παρέλθει και τα συμβάντα μετάβασης χρόνου.
Πώς να μεταγλωττίσετε και να εγκαταστήσετε λογισμικό από την πηγή στο Linux
Διαβάστε Επόμενο
Σχετικά θέματα
- Προγραμματισμός
- Προγραμματισμός
- Συμβουλές Linux
Σχετικά με τον Συγγραφέα
Ένας μηχανικός και προγραμματιστής λογισμικού που είναι λάτρης των μαθηματικών και της τεχνολογίας. Πάντα του άρεσαν οι υπολογιστές, τα μαθηματικά και η φυσική. Έχει αναπτύξει έργα μηχανών παιχνιδιών καθώς και μηχανική μάθηση, τεχνητά νευρωνικά δίκτυα και βιβλιοθήκες γραμμικής άλγεβρας. Επιπλέον, συνεχίζει να εργάζεται σε μηχανική μάθηση και γραμμικούς πίνακες.
Εγγραφείτε στο ενημερωτικό μας δελτίο
Εγγραφείτε στο ενημερωτικό μας δελτίο για συμβουλές τεχνολογίας, κριτικές, δωρεάν ebook και αποκλειστικές προσφορές!
Κάντε κλικ εδώ για να εγγραφείτε