*[Διεργασίες](../perlfunc-by-category.md)* # alarm Προγραμματίζει την παράδοση ενός `SIGALRM` στην τρέχουσα διεργασία μετά από έναν ακέραιο αριθμό δευτερολέπτων πραγματικού χρόνου. Η `alarm` οπλίζει έναν μοναδικό χρονομετρητή αντίστροφης μέτρησης ανά διεργασία. Όταν λήξει ο χρονομετρητής, ο πυρήνας παραδίδει το `SIGALRM`· τι θα συμβεί στη συνέχεια εξαρτάται εξ ολοκλήρου από τον εγκατεστημένο χειριστή σήματος στο [`%SIG`](../perlvar.md). Ο χρονομετρητής τρέχει σε πραγματικό χρόνο, όχι σε χρόνο CPU, οπότε μια διεργασία που κοιμάται ή είναι μπλοκαρισμένη λαμβάνει το σήμα στην ώρα της (με επιφύλαξη μικρών αποκλίσεων χρονοπρογραμματισμού). ## Σύνοψη ```perl alarm SECONDS alarm ``` Χωρίς όρισμα, χρησιμοποιείται η τιμή του [`$_`](../perlvar.md). ## Τι επιστρέφεται Ο αριθμός των δευτερολέπτων που απέμεναν στον **προηγούμενο** χρονομετρητή, ή `0` αν δεν εκκρεμούσε χρονομετρητής. Αυτό επιτρέπει να αποθηκεύσετε και να επαναφέρετε το alarm ενός καλούντος γύρω από μια εμφωλευμένη χρονομετρημένη λειτουργία: ```perl my $prev = alarm 10; # ... do something that must finish in 10s ... alarm $prev; # restore caller's timer ``` Η `alarm 0` ακυρώνει κάθε εκκρεμή χρονομετρητή και επιστρέφει τα δευτερόλεπτα που είχαν απομείνει σε αυτόν. ## Καθολική κατάσταση που επηρεάζει - [`%SIG`](../perlvar.md) — η θυρίδα `ALRM` ονοματίζει τον χειριστή που καλείται όταν ενεργοποιείται ο χρονομετρητής. Χωρίς χειριστή, η προεπιλεγμένη συμπεριφορά του `SIGALRM` είναι ο τερματισμός της διεργασίας. - [`$_`](../perlvar.md) — διαβάζεται όταν η `alarm` καλείται χωρίς όρισμα. - [`$@`](../perlvar.md) — μεταφέρει το μήνυμα `die` έξω από το κανονικό ιδίωμα `eval { alarm ...; ...; alarm 0 }`. - [`$!`](../perlvar.md) — μια μπλοκαριστική κλήση συστήματος που διακόπτεται από `SIGALRM` θέτει το `$!` σε `EINTR`, **αλλά** η Perl επανεκκινεί αυτόματα πολλές κλήσεις συστήματος σε ορισμένα συστήματα, οπότε δεν μπορείτε να βασιστείτε ότι θα δείτε `EINTR`. Χρησιμοποιήστε [`eval`](eval.md) / [`die`](die.md) αντ” αυτού (δείτε παρακάτω). ## Το κανονικό ιδίωμα χρονικού ορίου Χρησιμοποιήστε την `alarm` με [`eval`](eval.md) και [`die`](die.md) για να βάλετε ανώτατο όριο πραγματικού χρόνου σε οποιοδήποτε μπλοκ κώδικα, περιλαμβανομένης μπλοκαριστικής I/O: ```perl eval { local $SIG{ALRM} = sub { die "timeout\n" }; # \n matters alarm $timeout; my $nread = sysread $sock, $buf, 4096; alarm 0; # cancel on success }; if ($@) { die $@ unless $@ eq "timeout\n"; # rethrow others # ... handle timeout ... } ``` Τρεις λεπτομέρειες είναι κρίσιμες: - Η [`local`](local.md) περιορίζει το εμβέλειο του χειριστή στο μπλοκ `eval` ώστε να μη διαρρέει στον καλούντα. - Το `\n` στο `"timeout\n"` καταστέλλει το επίθεμα αρχείου/γραμμής που η [`die`](die.md) θα πρόσθετε διαφορετικά, καθιστώντας αξιόπιστο τον έλεγχο ακριβούς αντιστοιχίας στο `$@`. - Η `alarm 0` **μέσα** στο `eval` ακυρώνει τον χρονομετρητή στη διαδρομή επιτυχίας. Χωρίς αυτή, ένας χρονομετρητής που έμεινε οπλισμένος μπορεί να ενεργοποιηθεί κατά τη διάρκεια άσχετου κώδικα αφού επιστρέψει το `eval`. ## Παραδείγματα Απλή προθεσμία πραγματικού χρόνου: ```perl $SIG{ALRM} = sub { die "timeout\n" }; eval { alarm 5; my $line = <$slow_pipe>; # may block indefinitely alarm 0; }; warn "gave up waiting\n" if $@ eq "timeout\n"; ``` Εμφωλευμένοι χρονομετρητές — αποθήκευση και επαναφορά: ```perl my $saved = alarm 30; # remember caller's timer do_something(); alarm $saved; # put it back ``` Ακύρωση εκκρεμούς χρονομετρητή: ```perl my $left = alarm 0; # 0 if none was pending ``` Περιοδικός παλμός χωρίς `Time::HiRes`: ```perl $SIG{ALRM} = sub { print "tick\n"; alarm 1; # re-arm from inside the handler }; alarm 1; sleep 10; # do not mix sleep+alarm in real code ``` Καθυστέρηση μικρότερη του δευτερολέπτου — χρησιμοποιήστε `Time::HiRes`: ```perl use Time::HiRes qw(alarm); alarm 0.25; # 250 ms ``` ## Οριακές περιπτώσεις - **Μόνο ακέραια δευτερόλεπτα.** Η πυρηνική `alarm` αποκόπτει κλασματικά ορίσματα σε ακέραια δευτερόλεπτα. Για λεπτότερη ακρίβεια, φορτώστε το `Time::HiRes`, που εξάγει μια αντικαταστάτη `alarm` η οποία δέχεται αριθμούς κινητής υποδιαστολής. - **Απόκλιση χρονοπρογραμματισμού.** Το σήμα μπορεί να φτάσει έως και περίπου ένα δευτερόλεπτο νωρίτερα ή αργότερα λόγω του τρόπου με τον οποίο ο πυρήνας μετράει τα δευτερόλεπτα και προγραμματίζει τη διεργασία σας. Αντιμετωπίστε την `alarm N` ως ένα όριο *όχι-πριν-από-N-μείον-1*, όχι ως ακριβή προθεσμία. - **Ένας χρονομετρητής ανά διεργασία.** Κάθε κλήση `alarm` αντικαθιστά τον προηγούμενο χρονομετρητή· δεν υπάρχει ουρά. Η τιμή επιστροφής είναι η μόνη καταγραφή σας για ό,τι αντικαταστάθηκε. - **Η προεπιλεγμένη συμπεριφορά είναι μοιραία.** Χωρίς εγκατεστημένο χειριστή για το `ALRM`, η λήξη του χρονομετρητή τερματίζει τη διεργασία με `Alarm clock`. Εγκαταστήστε έναν χειριστή *πριν* οπλίσετε τον χρονομετρητή. - **Μην το συνδυάζετε με [`sleep`](sleep.md).** Σε πολλά συστήματα η [`sleep`](sleep.md) υλοποιείται πάνω στην `alarm`, οπότε το να οπλίσετε τη μία ακυρώνει την άλλη. Διαλέξτε μία ανά μπλοκ. - **Το `EINTR` δεν είναι αξιόπιστο.** Η Perl εγκαθιστά χειριστές σημάτων με `SA_RESTART` σε πολλές πλατφόρμες, οπότε ένα `SIGALRM` που διακόπτει μια μπλοκαριστική κλήση συστήματος επανεκκινεί διαφανώς την κλήση αντί να επιστρέψει με την [`$!`](../perlvar.md) σε `EINTR`. Ο φορητός τρόπος για την επιβολή προθεσμίας είναι [`eval`](eval.md) / [`die`](die.md) από τον χειριστή, όπως φαίνεται παραπάνω. - **Τα σήματα παραδίδονται μεταξύ των τελεστών Perl.** Μέσα σε σφιχτό βρόχο καθαρής Perl ο χειριστής τρέχει στο επόμενο ασφαλές σημείο, όχι ακαριαία· μια κλήση XS που δεσμεύει την CPU μπορεί να καθυστερήσει περαιτέρω την παράδοση. - **Η [`fork`](fork.md) εκκαθαρίζει τον χρονομετρητή.** Οι θυγατρικές διεργασίες ξεκινούν χωρίς εκκρεμές alarm ανεξάρτητα από το τι είχε οπλίσει η γονική. - **Η `exec` εκκαθαρίζει τον χρονομετρητή** στο Linux· η εικόνα της διεργασίας αντικατάστασης ξεκινά χωρίς εκκρεμές `SIGALRM`. ## Διαφορές από το upstream Πλήρως συμβατό με το upstream Perl 5.42. ## Δείτε επίσης - [`sleep`](sleep.md) — καθυστέρηση πραγματικού χρόνου· συχνά υλοποιείται πάνω στην `alarm`, οπότε οι δύο δεν συνδυάζονται - [`die`](die.md) — εγείρει από τον χειριστή `ALRM` την εξαίρεση που πιάνει η [`eval`](eval.md) για την υλοποίηση χρονικού ορίου - [`eval`](eval.md) — πιάνει το `die` από τον χειριστή και επιτρέπει στο πρόγραμμα να ανακάμψει από χρονικό όριο - [`%SIG`](../perlvar.md) — όπου εγκαθίσταται ο χειριστής `ALRM`· ο χειριστής αποφασίζει τι *σημαίνει* ο χρονομετρητής - [`select`](select.md) — η μορφή τεσσάρων ορισμάτων δέχεται χρονικό όριο κινητής υποδιαστολής και αποτελεί εναλλακτική της `alarm` για προθεσμίες I/O - `Time::HiRes` — απευθείας αντικαταστάτης της `alarm` που δέχεται αριθμούς κινητής υποδιαστολής μικρότερους του δευτερολέπτου μέσω `setitimer(2)`