wait#
Μπλοκάρει μέχρι να τερματιστεί οποιαδήποτε διεργασία παιδί και τη συγκομίζει.
Η wait είναι το απλούστερο front end για την υποκείμενη κλήση συστήματος wait(2). Αναστέλλει την τρέχουσα διεργασία μέχρι να τερματιστεί ένα από τα παιδιά της, συλλέγει την κατάσταση εξόδου αυτού του παιδιού στα $? και ${^CHILD_ERROR_NATIVE}, και επιστρέφει το PID του συγκομισμένου παιδιού. Αν δεν υπάρχουν παιδιά για αναμονή, επιστρέφει αμέσως -1. Είναι ακριβώς ισοδύναμη με την waitpid(-1, 0).
Σύνοψη#
my $pid = wait;
Τι επιστρέφεται#
Το PID του παιδιού που συγκομίστηκε (θετικός ακέραιος), ή -1 αν δεν έχουν απομείνει ασυγκόμιστα παιδιά σε αναμονή. Η κατάσταση του παιδιού πηγαίνει στο $?· η ακατέργαστη, εξειδικευμένη για το OS λέξη κατάστασης πηγαίνει στο ${^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-bit κατάσταση αναμονής του συγκομισμένου παιδιού (υψηλό byte: κωδικός εξόδου, χαμηλό byte: σήμα τερματισμού και σημαία core). Επίσης αναγνώσιμο ως$CHILD_ERRORυπόuse English.${^CHILD_ERROR_NATIVE}- η ακατέργαστη λέξη κατάστασης της πλατφόρμας, για καλούντες που θέλουν να χρησιμοποιήσουν τις POSIX μακροεντολές (WIFEXITED,WEXITSTATUS,WIFSIGNALED,WTERMSIG) από τοPOSIX.%SIG- αν το$SIG{CHLD}είναι ρυθμισμένο σε'IGNORE', ή χειριστής εντός του καλεί ο ίδιοςwait, το αποτέλεσμα αυτής της κλήσης αλλάζει. Δείτε Οριακές περιπτώσεις.
Παραδείγματα#
Δημιουργήστε ένα worker με 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, που είναι πιο φορητό από χειροκίνητη ολίσθηση bits:
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επειδή τα παιδιά έχουν φύγει προτού ο κώδικας χρήστη μπορέσει να την καλέσει. Το$?δεν τίθεται. Αν θέλετε και «fire-and-forget» παιδιά και αναφορά κατάστασης, χρησιμοποιήστε πραγματικό χειριστή, όχι'IGNORE'.Προσαρμοσμένος χειριστής
$SIG{CHLD}: αν ο χειριστής καλεί ο ίδιοςwait(ήwaitpid), μια μετέπειταwaitστην κύρια ροή δεν θα βρει τίποτα και θα επιστρέψει-1. Αποφασίστε εκ των προτέρων ποια διαδρομή κώδικα κάνει τη συγκομιδή.Αλληλεπίδραση με
qx//καιsystem: και τα δύο εσωτερικά κάνουν fork, exec, και αναμονή στο δικό τους παιδί. Ένας χειριστής$SIG{CHLD}που καλεί τυφλά τηνwaitμπορεί κατά λάθος να συγκομίσει αυτό το εσωτερικό παιδί κάτω από τη μύτη τηςqx//ή τηςsystem, αφήνοντάς τες ανίκανες να συλλέξουν την κατάσταση και επιστρέφοντας τυπικά-1με το$!ρυθμισμένο σεECHILD. Οι χειριστές θα πρέπει να επαναλαμβάνουν μεwaitpid(-1, WNOHANG)και να ενεργούν μόνο σε PIDs που αναγνωρίζουν.Το
$?γράφεται μόνο σε επιτυχημένη συγκομιδή. Μετά από επιστροφή-1, το$?διατηρεί ό,τι είχε πριν την κλήση. Μην το επιθεωρείτε εκτός αν ηwaitεπέστρεψε θετικό PID.Διακοπή από σήμα: αν παραδοθεί σήμα ενώ η
waitείναι μπλοκαρισμένη και ο χειριστής επιστρέψει φυσιολογικά, η Perl επανεκκινεί την αναμονή - δεν βλέπετεEINTRσε επίπεδο Perl. Αν ο χειριστής κάνειdieήexit, ο έλεγχος εγκαταλείπει τηwaitμε τον συνηθισμένο τρόπο για αυτόν τον μηχανισμό.Threaded builds: η
waitπεριμένει παιδιά της τρέχουσας διεργασίας, όχι παιδιά συγκεκριμένου νήματος. Σε πρόγραμμα πολλαπλών νημάτων, το νήμα που κάνει τη συγκομιδή είναι όποιο κάλεσε πρώτο τηwait.Η τιμή επιστροφής είναι PID, όχι λογική τιμή: το
if (wait) { ... }είναι αληθές τόσο για επιτυχημένες συγκομιδές όσο και για-1. Συγκρίνετε πάντα με0ή ελέγχετε ρητά> 0, όπως στη μορφή βρόχου παραπάνω.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
waitpid- αναμονή συγκεκριμένου παιδιού, ή poll χωρίς μπλοκάρισμα μεWNOHANG· ηwaitείναι η μορφήwaitpid(-1, 0)fork- δημιουργεί τα παιδιά που συγκομίζει ηwaitexec- αυτό που τυπικά καλεί ένα forked παιδί για να γίνει διαφορετικό πρόγραμμαsystem- fork + exec + wait σε μία κλήση· χρησιμοποιεί τη δική της εσωτερικήwaitκαι ρυθμίζει το$?για εσάςkill- στέλνει σήμα σε παιδί που δεν θέλετε πλέον να περιμένετε$?- εκεί όπου τοποθετείται η κατάσταση του συγκομισμένου παιδιού, κωδικοποιημένη ως υψηλό byte κωδικού εξόδου συν χαμηλό byte σήματος/core