alarm#
תזמון SIGALRM שיישלח לתהליך הנוכחי לאחר מספר שלם של שניות שעון־קיר.
alarm דורך טיימר ספירה לאחור יחיד לכל תהליך. כאשר הטיימר פוקע, הקרנל שולח SIGALRM; מה שקורה אחר כך תלוי כולו במטפל האות המותקן ב־%SIG. הטיימר רץ בזמן שעון־קיר, לא בזמן CPU, כך שתהליך ישן או חסום עדיין מקבל את האות בזמן (בכפוף ל־jitter של התזמון).
תקציר#
alarm SECONDS
alarm
ללא ארגומנט, נעשה שימוש בערך שב־$_.
מה מוחזר#
מספר השניות שנותרו על הטיימר הקודם, או 0 אם לא היה טיימר ממתין. זה מאפשר לשמור ולשחזר את ה־alarm של הקורא לאורך פעולה מתוזמנת מקוננת:
my $prev = alarm 10;
# ... do something that must finish in 10s ...
alarm $prev; # restore caller's timer
alarm 0 מבטל כל טיימר ממתין ומחזיר את השניות שנותרו עליו.
מצב גלובלי שהפונקציה נוגעת בו#
%SIG— תאALRMנושא את שם המטפל שמוזעק כאשר הטיימר יורה. ללא מטפל, ברירת המחדל שלSIGALRMהיא לסיים את התהליך.$_— נקרא כאשרalarmנקרא ללא ארגומנט.$@— נושא את הודעת ה־dieמתוך הניב הקנוניeval { alarm ...; ...; alarm 0 }.$!— קריאת מערכת חוסמת שנקטעה על ידיSIGALRMקובעת את$!ל־EINTR, אך Perl מפעיל מחדש קריאות מערכת רבות אוטומטית במערכות מסוימות, ולכן אי אפשר להסתמך על ראייתEINTR. יש להשתמש ב־eval/dieבמקום זאת (ראו להלן).
הניב הקנוני ל־timeout#
שימוש ב־alarm יחד עם eval ו־die להטלת תקרת זמן שעון־קיר על כל בלוק קוד, לרבות I/O חוסם:
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 ...
}
שלושה פרטים נושאים משקל:
דוגמאות#
תאריך יעד פשוט בשעון־קיר:
$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";
טיימרים מקוננים — שמירה ושחזור:
my $saved = alarm 30; # remember caller's timer
do_something();
alarm $saved; # put it back
ביטול טיימר ממתין:
my $left = alarm 0; # 0 if none was pending
טיק מחזורי ללא Time::HiRes:
$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:
use Time::HiRes qw(alarm);
alarm 0.25; # 250 ms
מקרי קצה#
שניות שלמות בלבד. ה־
alarmשבליבה קוטם ארגומנטים שבריריים לשניות שלמות. לרזולוציה דקה יותר, יש לטעון אתTime::HiRes, אשר מייצאalarmחליפי המקבל מספרים בנקודה צפה.jitter של תזמון. האות עשוי להגיע מוקדם או מאוחר עד כשנייה אחת בגלל אופן ספירת השניות בקרנל ותזמון התהליך. יש להתייחס ל־
alarm Nכאל גבול לא־לפני־N־פחות־1, לא כאל תאריך יעד מדויק.טיימר אחד לכל תהליך. כל קריאת
alarmמחליפה את הטיימר הקודם; אין תור. הערך המוחזר הוא הרישום היחיד של מה שנדרס.ברירת המחדל קטלנית. ללא מטפל מותקן עבור
ALRM, פקיעת הטיימר מסיימת את התהליך עםAlarm clock. יש להתקין מטפל לפני דריכת הטיימר.אין לערבב עם
sleep. במערכות רבותsleepממומש על גביalarm, ולכן דריכת אחד מהם דורסת את השני. יש לבחור אחד לכל בלוק.EINTRאינו אמין. Perl מתקין מטפלי אותות עםSA_RESTARTבפלטפורמות רבות, ולכןSIGALRMהקוטע קריאת מערכת חוסמת מפעיל מחדש את הקריאה בשקיפות במקום לחזור כאשר$!מוגדר כ־EINTR. הדרך הניידת לאכוף תאריך יעד היאeval/dieמתוך המטפל, כפי שמודגם לעיל.אותות נשלחים בין אופים של Perl. בתוך לולאה צפופה ב־Perl טהור המטפל רץ בנקודה הבטוחה הבאה, לא באופן מיידי; קריאת XS עתירת CPU יכולה לדחות את המסירה עוד יותר.
forkמנקה את הטיימר. תהליכי בן מתחילים ללא alarm ממתין ללא קשר למה שההורה דרך.execמנקה את הטיימר ב־Linux; דמות התהליך החליפית מתחילה ללאSIGALRMממתין.
הבדלים מן ה-upstream#
תואם מלא ל־Perl 5.42 upstream.
ראו גם#
sleep— השהיית שעון־קיר; לעתים קרובות ממומש על גביalarm, ולכן השניים אינם משתלביםdie— מעלה את החריגה ממטפלALRMש־evalתופס כדי לממש timeouteval— תופס את ה־dieמהמטפל ומאפשר לתוכנית להתאושש מ־timeout%SIG— המקום שבו מטפלALRMמותקן; המטפל מחליט מה הטיימר משמעותוselect— הצורה בעלת ארבעת הארגומנטים מקבלת timeout בנקודה צפה ומהווה חלופה ל־alarmעבור תאריכי יעד של I/OTime::HiRes— חליףalarmישיר המקבל מספרים בנקודה צפה תת־שנייתיים באמצעותsetitimer(2)