Διεργασίες

waitpid#

Περιμένει να τερματίσει συγκεκριμένη διεργασία-παιδί και τη συλλέγει.

Η waitpid είναι το στοχευμένο αντίστοιχο της wait. Ενώ η wait συλλέγει οποιοδήποτε παιδί και μπλοκάρει μέχρι ένα να εξέλθει, η waitpid σας επιτρέπει να ονομάσετε ποιο παιδί (ή ποια ομάδα παιδιών) να περιμένετε, και σας επιτρέπει να δημοσκοπείτε αντί να μπλοκάρετε, περνώντας WNOHANG στα FLAGS. Η κατάσταση εξόδου του παιδιού που συλλέχθηκε προσγειώνεται στην $?, όπως ακριβώς και με την wait.

Σύνοψη#

use POSIX ":sys_wait_h";

waitpid $pid, 0;                   # block until $pid exits
waitpid $pid, WNOHANG;             # poll: is $pid done yet?
waitpid -1,  WNOHANG;              # reap any ready zombie, don't block

Τι επιστρέφεται#

  • Το PID του παιδιού που συλλέχθηκε σε επιτυχία.

  • 0 όταν είναι ορισμένο το WNOHANG και υπάρχει τουλάχιστον ένα παιδί που ταιριάζει αλλά κανένα δεν έχει τερματίσει ακόμη - δηλαδή «τρέχει ακόμη, δοκιμάστε αργότερα».

  • -1 όταν καμία διεργασία-παιδί δεν ταιριάζει με το PID (δεν υπήρξε ποτέ, έχει ήδη συλλεχθεί, ή - σε συστήματα που κάνουν αυτόματη συλλογή - συγκομίστηκε από τον πυρήνα χωρίς τη βοήθεια της Perl).

Η κατάσταση εξόδου του παιδιού γράφεται στην $? και η ωμή OS-native κατάσταση στην ${^CHILD_ERROR_NATIVE} σε κάθε επιτυχημένη συλλογή. Αποκωδικοποιήστε την $? με τον ίδιο τρόπο όπως μετά από wait ή κλήση με backticks:

my $reaped = waitpid $pid, 0;
if ($reaped > 0) {
    my $exit   = $? >> 8;
    my $signal = $? & 127;
    my $core   = $? & 128;
}

Τι σημαίνει το PID#

Το PID επιλέγει ποια παιδιά είναι πρόθυμη να συλλέξει η waitpid:

  • Θετικό PID - περιμένει για το συγκεκριμένο παιδί. Επιστροφή -1 σημαίνει ότι δεν υπάρχει τέτοιο παιδί (το έχετε ήδη συλλέξει, ή δεν ήταν ποτέ δικό σας).

  • 0 - περιμένει για οποιοδήποτε παιδί στην τρέχουσα ομάδα διεργασιών. Χρήσιμο όταν το πρόγραμμά σας έχει ενταχθεί σε ομάδα διεργασιών με άλλες συνεργαζόμενες διεργασίες και θέλετε να συγκομίζετε μόνο τα δικά σας.

  • -1 - περιμένει για οποιοδήποτε παιδί, ίδια εμβέλεια με την wait.

  • Μικρότερο από -1 - περιμένει για οποιοδήποτε παιδί του οποίου το ID ομάδας διεργασιών ισούται με την απόλυτη τιμή του PID. Η waitpid -$pgid, 0 περιμένει για οποιοδήποτε μέλος της ομάδας διεργασιών $pgid.

Τα FLAGS είναι bitmask. Η φορητή σημαία είναι το WNOHANG, που κάνει την κλήση μη μπλοκαριστική: αν κανένα παιδί που ταιριάζει δεν έχει εξέλθει, η waitpid επιστρέφει 0 αμέσως αντί να κοιμηθεί. FLAGS ίσο με 0 σημαίνει «μπλόκαρε μέχρι κάτι να είναι συλλέξιμο», και υλοποιείται σε κάθε πλατφόρμα όπου τρέχει η Perl - ακόμη και σε αυτές χωρίς εγγενή κλήση συστήματος waitpid(2), όπου η Perl την εξομοιώνει θυμούμενη τις καταστάσεις εξόδου παιδιών που έχει ήδη δει.

Καθολική κατάσταση που επηρεάζει#

  • $? - τίθεται στην κατάσταση εξόδου του παιδιού που συλλέχθηκε (μετατοπισμένη: το υψηλό byte = κωδικός exit, τα χαμηλά 7 bits = σήμα, το bit 0x80 = σημαία core-dumped).

  • ${^CHILD_ERROR_NATIVE} - τίθεται στην ωμή OS-native λέξη κατάστασης, πριν η Perl την κανονικοποιήσει σε $?.

Καμία από τις δύο μεταβλητές δεν αγγίζεται όταν η waitpid επιστρέφει 0 (WNOHANG και τίποτα έτοιμο) ή -1 (κανένα παιδί που να ταιριάζει).

Παραδείγματα#

Μπλοκάρισμα μέχρι γνωστό παιδί να τελειώσει, και κατόπιν επιθεώρηση του κωδικού εξόδου του:

my $pid = fork // die "fork: $!";
if ($pid == 0) {
    exec "/usr/bin/gzip", "big.log" or die "exec: $!";
}
waitpid $pid, 0;
die "gzip failed with status ", $? >> 8 if $?;

Δημοσκόπηση χωρίς μπλοκάρισμα - χρήσιμη μέσα σε βρόχο γεγονότων ή χειριστή SIGCHLD:

use POSIX ":sys_wait_h";

sub harvest_children {
    while ((my $kid = waitpid -1, WNOHANG) > 0) {
        warn "child $kid exited with ", $? >> 8, "\n";
    }
}

Το κλασικό ιδίωμα «συλλογή κάθε εκκρεμούς zombie, χωρίς μπλοκάρισμα»:

use POSIX ":sys_wait_h";
1 while waitpid(-1, WNOHANG) > 0;

Αναμονή μόνο για παιδιά σε συγκεκριμένη ομάδα διεργασιών. Πρώτα setpgid, και κατόπιν στοχεύστε την ομάδα κάνοντας αρνητικό το ID της:

my $leader = fork // die "fork: $!";
if ($leader == 0) {
    setpgid 0, 0;        # become process-group leader
    exec @worker_cmd or die "exec: $!";
}
setpgid $leader, $leader;  # parent matches, races with child

# ... later, reap any member of that group:
while ((my $kid = waitpid -$leader, WNOHANG) > 0) {
    log_exit($kid, $?);
}

Διάκριση των τριών τιμών επιστροφής σε ένα σημείο:

my $r = waitpid $pid, WNOHANG;
if    ($r == $pid) { finalize_child($pid, $?) }
elsif ($r == 0)    { still_running($pid) }
elsif ($r == -1)   { warn "no such child $pid (already reaped?)" }

Οριακές περιπτώσεις#

  • Το WNOHANG απαιτεί use POSIX. Η σταθερά δεν είναι ενσωματωμένη στην Perl· προέρχεται από το άρθρωμα POSIX, τυπικά μέσω use POSIX ":sys_wait_h";. Το να γράφετε γυμνό ακέραιο (waitpid $pid, 1) λειτουργεί στο Linux αλλά δεν είναι φορητό και αποκρύπτει την πρόθεση.

  • Το $SIG{CHLD} = 'IGNORE' μπαίνει σε race με την waitpid. Όταν λέτε στον πυρήνα να συλλέγει αυτόματα τα παιδιά, δεν μένει τίποτα για να βρει η waitpid - επιστρέφει -1 με την $! ορισμένη σε ECHILD. Επιλέξτε μία στρατηγική συλλογής ανά πρόγραμμα, όχι και τις δύο.

  • PIDs που έχουν ήδη συλλεχθεί επιστρέφουν -1. Το PID μεμονωμένου παιδιού μπορεί να συλλεχθεί μόνο μία φορά· μετά από αυτό ξεχνιέται. Αν δώσετε το ίδιο PID στην waitpid δύο φορές, η δεύτερη κλήση επιστρέφει -1.

  • Το αρνητικό PID είναι ομάδα διεργασιών, όχι «οποιοδήποτε εκτός από αυτό». Η waitpid -1234, 0 περιμένει για μέλη της ομάδας διεργασιών 1234, όχι «κάθε παιδί εκτός από το PID 1234». Αναγνώστες ανεξοικείωτοι με τη σύμβαση POSIX συχνά το παρερμηνεύουν.

  • Η WNOHANG με PID = -1 είναι η πρότυπη μορφή «αποστράγγιση της ουράς zombies». Σε συνδυασμό με βρόχο while συλλέγει κάθε παιδί που έχει ήδη εξέλθει και σταματά μόλις ο πυρήνας δεν έχει τίποτα άλλο να δώσει πίσω.

  • Η τιμή επιστροφής -1 μπορεί επίσης να σημαίνει αυτόματη συλλογή. Σε συστήματα διαμορφωμένα να συλλέγουν αυτόματα τα παιδιά (π.χ. χειριστής $SIG{CHLD} = 'IGNORE' εγκατεστημένος στην έναρξη), η waitpid δεν βλέπει κανένα παιδί και επιστρέφει -1 ακόμη και για PID που μόλις κάνατε fork. Δείτε το perlipc για τις σημειώσεις πλατφόρμας.

  • Η μπλοκαριστική αναμονή είναι πάντα διαθέσιμη. Ακόμη και σε πλατφόρμες χωρίς εγγενή κλήση συστήματος waitpid(2) ή wait4(2), η waitpid PID, 0 λειτουργεί - η Perl την εξομοιώνει διατηρώντας τις καταστάσεις παιδιών που έχει ήδη συλλέξει.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • wait - μπλοκάρει για οποιοδήποτε παιδί· ισοδύναμη με waitpid -1, 0 σε συστήματα που την υποστηρίζουν

  • fork - δημιουργεί τα παιδιά που αργότερα θα συλλέξετε με waitpid

  • kill - στέλνει σήμα στα ίδια PIDs και ομάδες διεργασιών που δέχεται η waitpid

  • $? - κατάσταση εξόδου του παιδιού που συλλέχθηκε· αποκωδικοποιήστε ως $? >> 8 για τον κωδικό εξόδου, $? & 127 για το σήμα

  • ${^CHILD_ERROR_NATIVE} - ωμή OS-native λέξη κατάστασης για το ίδιο παιδί

  • POSIX - πηγή του WNOHANG και του υπόλοιπου :sys_wait_h