wait#
חסימה עד שתהליך־ילד כלשהו יוצא ואיסופו.
wait הוא ממשק הקצה הפשוט ביותר לקריאת המערכת הבסיסית wait(2). הוא משעה את התהליך הנוכחי עד שאחד מילדיו מסתיים, אוסף את סטטוס היציאה של אותו ילד לתוך $? ו־${^CHILD_ERROR_NATIVE}, ומחזיר את ה־PID של הילד שנאסף. אם אין ילדים להמתין להם, הוא מחזיר -1 מיד. הוא שקול בדיוק ל־waitpid(-1, 0).
תקציר#
my $pid = wait;
מה מקבלים בחזרה#
ה־PID של הילד שנאסף (מספר שלם חיובי), או -1 אם אין ילדים לא־אסופים שנותרו להמתין להם. סטטוס הילד עובר לתוך $?; מילת הסטטוס הגולמית הספציפית למערכת ההפעלה עוברת לתוך ${^CHILD_ERROR_NATIVE}.
לפענוח $? אחרי wait מוצלח:
my $exit = $? >> 8; # normal exit code (0..255)
my $signal = $? & 0x7f; # termination signal, if any
my $core = $? & 0x80; # core-dump flag
החזרה של -1 לא תמיד משמעה ״מעולם לא היו ילדים״ - היא יכולה גם להיות ״משהו כבר אסף אותם בשבילי״ (ראו למטה).
מצב גלובלי שהוא נוגע בו#
$?- מוגדר לסטטוס ההמתנה של הילד שנאסף ברוחב 16 ביט (בית עליון: קוד היציאה, בית תחתון: אות הסיום ודגל core). ניתן לקריאה גם כ־$CHILD_ERRORתחתuse English.${^CHILD_ERROR_NATIVE}- מילת הסטטוס הגולמית של הפלטפורמה, עבור קוראים שרוצים להשתמש במאקרואים של POSIX (WIFEXITED,WEXITSTATUS,WIFSIGNALED,WTERMSIG) מ־POSIX.%SIG- אם$SIG{CHLD}מוגדר ל־'IGNORE', או שמטפל בו קורא ל־waitבעצמו, תוצאת קריאה זו משתנה. ראו מקרי קצה.
דוגמאות#
בצעו fork לעובד, עשו משהו, ואז אספו אותו:
my $pid = fork // die "fork: $!";
if ($pid == 0) {
# child
exec "/usr/bin/true" or die "exec: $!";
}
my $reaped = wait; # blocks until the child exits
die "unexpected pid" if $reaped != $pid;
printf "child %d exited %d\n", $reaped, $? >> 8;
איסוף כל ילד תלוי ועומד בלולאה. wait מחזיר -1 ברגע שלתהליך לא נותרו ילדים:
while ((my $kid = wait) > 0) {
warn "reaped $kid, status " . ($? >> 8) . "\n";
}
הבחנה בין יציאה רגילה לסיום באות:
my $pid = wait;
if ($pid > 0) {
if ($? == 0) { say "clean exit" }
elsif ($? & 0x7f) { say "killed by signal " . ($? & 0x7f) }
else { say "exit " . ($? >> 8) }
}
פענחו את מילת הסטטוס המקומית עם מאקרואים של POSIX, מה שנייד יותר מהזזת ביטים ידנית:
use POSIX ":sys_wait_h";
my $pid = wait;
if ($pid > 0 && WIFEXITED(${^CHILD_ERROR_NATIVE})) {
say "exit code: ", WEXITSTATUS(${^CHILD_ERROR_NATIVE});
}
איסוף לא־חוסם של כל zombie ממתין - השתמשו ב־waitpid עם WNOHANG, לא ב־wait:
use POSIX ":sys_wait_h";
1 while waitpid(-1, WNOHANG) > 0;
מקרי קצה#
אין ילדים להמתין להם: מחזיר
-1מיד.waitאינו חוסם במקרה זה - הוא חוסם רק כאשר לפחות ילד אחד עדיין חי ולא־אסוף.$SIG{CHLD} = 'IGNORE': במערכות POSIX זה מבקש מהקרנל לבצע איסוף־אוטומטי של ילדים. תחת הגדרה זו,waitכמעט תמיד מחזיר-1משום שהילדים נעלמו לפני שקוד המשתמש יכול לקרוא לו.$?אינו מוגדר. אם רוצים גם ילדים בסגנון שגר־ושכח וגם דיווח סטטוס, השתמשו במטפל אמיתי, לא ב־'IGNORE'.מטפל
$SIG{CHLD}מותאם אישית: אם המטפל קורא ל־wait(אוwaitpid) בעצמו,waitעוקב בזרימה הראשית ימצא שדבר לא נותר ויחזיר-1. החליטו מראש איזה מסלול קוד מבצע את האיסוף.אינטראקציה עם
qx//ו־system: שני אלה מבצעים פנימית fork, exec, וממתינים על הילד שלהם. מטפל$SIG{CHLD}שקורא ל־waitבעיוורון יכול בטעות לאסוף את הילד הפנימי ההוא מתחת ל־qx//אוsystem, ולהשאיר אותם בלתי־מסוגלים לאסוף את הסטטוס ובדרך כלל מחזירים-1כאשר$!מוגדר ל־ECHILD. מטפלים צריכים ללולל עםwaitpid(-1, WNOHANG)ולפעול רק על PID־ים שהם מזהים.$?נכתב רק באיסוף מוצלח. אחרי החזרה של-1,$?שומר על מה שהיה לו לפני הקריאה. אל תבחנו אותו אלא אםwaitהחזיר PID חיובי.הופרע על־ידי אות: אם אות נמסר בעוד
waitחסום והמטפל חוזר כרגיל, Perl מאתחל מחדש את ההמתנה - לא רואיםEINTRברמת Perl. אם המטפל מבצעdieאוexit, הבקרה עוזבת אתwaitבאופן הרגיל לאותו מנגנון.בנייות מרובות־thread:
waitממתין לילדים של התהליך הנוכחי, לא לילדים של thread ספציפי. בתוכנית מרובת־thread thread האיסוף הוא זה שקרא ל־waitראשון.ערך ההחזרה הוא PID, לא בוליאני:
if (wait) { ... }הוא אמת גם לאיסופים מוצלחים וגם ל־-1. תמיד השוו ל־0או בדקו> 0במפורש, כמו בצורת הלולאה לעיל.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
waitpid- המתנה לילד ספציפי, או poll לא־חוסם עםWNOHANG;waitהוא הצורהwaitpid(-1, 0)fork- יצירת הילדים ש־waitאוסףexec- מה שילד forked קורא בדרך כלל כדי להפוך לתוכנית אחרתsystem- fork + exec + wait בקריאה אחת; משתמש ב־waitפנימי משלו ומגדיר את$?עבורכםkill- שליחת אות לילד שלא רוצים יותר להמתין לו$?- היכן שסטטוס הילד שנאסף נוחת, מקודד כבית עליון של קוד יציאה ובית תחתון של אות/core