Exec με παραδείγματα Linux. Μάθετε πώς να δημιουργείτε μια διαδικασία UNIX. Καταχώριση 1. Έξοδος της εντολής ps

EXEC(2)

ΟΝΟΜΑ
exec: execl, execv, execle, execve, execlp, εκτέλεση αρχείου execvp

ΣΥΝΤΑΞΗ

Int execl (διαδρομή, arg0, arg1, ..., argn, (char*) 0) char *path, *arg0, *arg1, ..., *argn; int execv (διαδρομή, argv) char *path, *argv ; int execle (διαδρομή, arg0, arg1, ..., argn, (char*) 0, envp) char *path, *arg0, *arg1, ..., *argn, *envp ; int execve (διαδρομή, argv, envp) char *path, *argv , *envp ; int execlp (αρχείο, arg0, arg1, ..., argn, (char*) 0) char *file, *arg0, *arg1, ..., *argn; int execvp (αρχείο, argv) char *file, *argv ;

ΠΕΡΙΓΡΑΦΗ
Όλες οι μορφές κλήσης συστήματος exec μετατρέπουν τη διαδικασία κλήσης σε νέα διαδικασία, το οποίο είναι κατασκευασμένο από ένα κανονικό εκτελέσιμο αρχείο, το οποίο στο εξής ονομάζεται νέο εκτελέσιμο αρχείο. Το εκτελέσιμο αρχείο αποτελείται από μια κεφαλίδα [βλ a.out(4)], τμήμα εντολών (.text) και δεδομένα. Τα δεδομένα αποτελούνται από ένα αρχικοποιημένο (.data) και ένα μη αρχικοποιημένο (.bss) τμήμα. Εάν η κλήση συστήματος exec πετύχει, δεν μπορεί να επιστρέψει επειδή η διαδικασία κλήσης έχει ήδη αντικατασταθεί από μια νέα διαδικασία.

Όταν εκτελείτε ένα πρόγραμμα C, το ονομάζετε ως εξής:

Κύρια (argc, argv, envp) int argc; char **argv, **envp;

όπου το argc είναι ίσο με τον αριθμό των ορισμάτων, το argv είναι ένας πίνακας δεικτών στα ίδια τα ορίσματα και το envp είναι ένας πίνακας δεικτών στις συμβολοσειρές χαρακτήρων που σχηματίζουν το περιβάλλον. Η σύμβαση είναι ότι το argc είναι τουλάχιστον 1 και το πρώτο στοιχείο του πίνακα argv δείχνει μια συμβολοσειρά χαρακτήρων που περιέχει το όνομα του νέου εκτελέσιμου αρχείου.

Τα ορίσματα στις κλήσεις συστήματος της ομάδας exec έχουν την ακόλουθη σημασία.

Το όρισμα διαδρομής καθορίζει το όνομα διαδρομής του νέου εκτελέσιμου αρχείου.

Όπως και η διαδρομή, το όρισμα αρχείου καθορίζει ένα νέο εκτελέσιμο αρχείο, αλλά η διαδρομή αυτού του αρχείου προσδιορίζεται κοιτάζοντας τους καταλόγους που έχουν περάσει μεταβλητή περιβάλλοντοςΠΑΘ [βλ περιβάλλον(5) ]. Το περιβάλλον διατηρείται από το κέλυφος [βλέπε sh(1) ].

Τα ορίσματα arg0, arg1, ..., argn είναι δείκτες σε συμβολοσειρές χαρακτήρων που οριοθετούνται με null byte. Αυτές οι αλυσίδες αποτελούν τη λίστα των ορισμάτων που είναι διαθέσιμα στη νέα διαδικασία. Κατά σύμβαση, στο ελάχιστο arg0 πρέπει να υπάρχει και να δείχνει μια σειρά χαρακτήρων ίση με τη διαδρομή (ή τελευταίο συστατικόμονοπάτι).

Ο πίνακας argv περιέχει δείκτες σε συμβολοσειρές χαρακτήρων που οριοθετούνται με null byte. Αυτές οι αλυσίδες αποτελούν τη λίστα των ορισμάτων που είναι διαθέσιμα στη νέα διαδικασία. Κατά σύμβαση, το argv πρέπει να περιέχει τουλάχιστον το πρώτο στοιχείο που δείχνει μια συμβολοσειρά χαρακτήρων ίση με τη διαδρομή (ή το τελευταίο στοιχείο της διαδρομής). Το τελευταίο κατειλημμένο στοιχείο του πίνακα argv πρέπει να ακολουθείται από έναν μηδενικό δείκτη.

Ο πίνακας envp περιέχει δείκτες σε συμβολοσειρές χαρακτήρων που οριοθετούνται με null byte. Αυτές οι αλυσίδες αποτελούν το περιβάλλον της νέας διαδικασίας. Το τελευταίο κατειλημμένο στοιχείο του πίνακα envp πρέπει να ακολουθείται από έναν μηδενικό δείκτη.

Πριν ξεκινήσετε οποιαδήποτε εκτέλεση προγράμματος, στο εξωτερικό περιβάλλον μεταβλητής, η περιγραφή του οποίου μοιάζει

Εξωτερικό χαρακτήρα **περιβάλλον;

τοποθετείται η διεύθυνση μιας σειράς δεικτών στις συμβολοσειρές των συμβόλων που σχηματίζουν το περιβάλλον της διεργασίας. Χρησιμοποιώντας αυτήν τη μεταβλητή (καθώς και χρησιμοποιώντας το όρισμα envp στο main), μπορείτε πάντα να έχετε πρόσβαση στο περιβάλλον σε μια νέα διαδικασία, ανεξάρτητα από την έκδοση της κλήσης συστήματος exec που χρησιμοποιήθηκε. Η μόνη διαφορά είναι ότι στην περίπτωση κλήσεων execle και execve, το περιβάλλον της νέας διεργασίας καθορίζεται ρητά και σε άλλες περιπτώσεις κληρονομείται από τη διαδικασία κλήσης.

Τα αρχεία που ανοίγουν στη διαδικασία κλήσης παραμένουν ανοιχτά στη νέα διαδικασία, εκτός από αυτά που έχουν οριστεί η σημαία "close on exec" [βλ. fcntl(2) ]. Εάν το αρχείο παραμείνει ανοιχτό, ο δείκτης στην τρέχουσα θέση στο αρχείο διατηρείται.

Η απόκριση στα σήματα διατηρείται, εκτός από το ότι τα σήματα που παρεμποδίστηκαν στη διαδικασία κλήσης προκαλούν τον τερματισμό της νέας διαδικασίας [βλ. σήμα(2) ].

Στην περίπτωση που η απόκριση σήματος ορίστηκε καλώντας το sigset(2) και προσδιορίστηκε ως SIG_DFL, SIG_IGN ή SIG_HOLD, αυτή η απόκριση κληρονομείται από τη διαδικασία κλήσης. Ωστόσο, εάν το σήμα υποκλαπεί, τότε η απόκριση SIG_DFL τίθεται και όλα τα λαμβανόμενα αλλά όχι επεξεργασμένα σήματα αυτού του τύπου παραμερίζονται.

Εάν το νέο εκτελέσιμο αρχείο έχει οριστεί το bit άδειας για επαναφορά του τρέχοντος αναγνωριστικού χρήστη [βλ chmod(2) ], τότε το πραγματικό αναγνωριστικό χρήστη της νέας διαδικασίας ορίζεται στο αναγνωριστικό κατόχου του νέου εκτελέσιμου αρχείου. Ομοίως, εάν το bit άδειας του νέου εκτελέσιμου έχει ρυθμιστεί για επαναφορά του ενεργού αναγνωριστικού ομάδας, τότε το ενεργό αναγνωριστικό ομάδας της νέας διαδικασίας ορίζεται στο αναγνωριστικό ομάδας του νέου εκτελέσιμου αρχείου. Το πραγματικό αναγνωριστικό χρήστη και το πραγματικό αναγνωριστικό ομάδας της νέας διαδικασίας κληρονομούνται από τη διαδικασία κλήσης.

Τα συνδεδεμένα τμήματα κοινόχρηστης μνήμης δεν κληρονομούνται από τη νέα διαδικασία [βλ shmop(2) ].

Η νέα διαδικασία έχει απενεργοποιήσει το προφίλ.

Επιπλέον, η νέα διαδικασία κληρονομεί τα ακόλουθα χαρακτηριστικά από τη διαδικασία που ονομάζεται exec:

  1. Τιμή προσαρμογής προτεραιότητας [βλ ωραίο (2) ].
  2. Αναγνωριστικό διαδικασίας.
  3. Αναγνωριστικό της γονικής διαδικασίας.
  4. Αναγνωριστικό ομάδας διεργασιών.
  5. semadj έννοιες [βλ semop(2) ].
  6. Αναγνωριστικό ομάδας τερματικού [βλ έξοδος (2) ].
  7. Trace mode [βλ ptrace(2) ].
  8. Χρόνος που απομένει μέχρι να χτυπήσει το ξυπνητήρι [βλ συναγερμός (2) ].
  9. Τρέχων κατάλογος εργασίας.
  10. Κατάλογος ρίζας.
  11. Μάσκα τρόπου δημιουργίας αρχείου [βλ. umask(2) ].
  12. Όριο μεγέθους αρχείου [βλ ulimit(2) ].
  13. Μετρητές χρόνου που δαπανάται για την εξυπηρέτηση αυτής της διαδικασίας (tms_utime, tms_stime, tms_cutime, tms_cstime) [βλ. φορές (2)].
  14. Αποκλεισμός πρόσβασης σε τμήματα αρχείων [βλ. fcntl(2) και lockf(3C) ].

Η κλήση συστήματος exec αποτυγχάνει και το στοιχείο ελέγχου επιστρέφει εάν ισχύει τουλάχιστον μία από τις ακόλουθες συνθήκες: Το στοιχείο διαδρομής του νέου εκτελέσιμου αρχείου δεν υπάρχει. Το στοιχείο διαδρομής του νέου εκτελέσιμου δεν είναι κατάλογος. Ένας από τους καταλόγους που παρατίθενται στη διαδρομή του νέου εκτελέσιμου αρχείου δεν είναι ορατός. Το νέο εκτελέσιμο αρχείο δεν είναι κανονικό αρχείο. Δεν υπάρχει άδεια για την εκτέλεση του νέου αρχείου. Το νέο αρχείο έχει δικαιώματα εκτέλεσης, αλλά η κεφαλίδα του δεν ξεκινά με έγκυρο μαγικό αριθμό [βλ α.έξω(4)]. Το νέο εκτελέσιμο αρχείο είναι προς το παρόν ανοιχτό για εγγραφή με κάποια διαδικασία. Η νέα διαδικασία απαιτεί περισσότερη μνήμη, από ό,τι επιτρέπει ο περιορισμός συστήματος MAXMEM. Το συνολικό μήκος της λίστας ορισμάτων υπερβαίνει το όριο συστήματος των 5120 byte. Λείπει ο απαιτούμενος εξοπλισμός. Μη έγκυρες διευθύνσεις ως ορίσματα. Ανεπαρκής μνήμη. Δεν επιτρέπεται η πρόσβαση εκτέλεσης στην απαιτούμενη κοινόχρηστη βιβλιοθήκη. Έγινε προσπάθεια απευθείας εκτέλεσης μιας κοινόχρηστης βιβλιοθήκης. Ένα σήμα παρεμποδίστηκε κατά τη διάρκεια μιας κλήσης exec. Το όρισμα διαδρομής δείχνει σεαπομακρυσμένος υπολογιστής , συνδέσεις με τις οποίες σεαυτή τη στιγμή

Οχι. Τα στοιχεία διαδρομής απαιτούν πολλαπλές κλήσεις σε απομακρυσμένους υπολογιστές.

int execle(char *fname, char *arg0, ..., char *argN, NULL, char *envp)

int execlp(char *fname, char *arg0, ..., char *argN, NULL)

int execlpe(char *fname, char *arg0, ..., char *argN, NULL, char *envp)

int execv(char *fname, char *arg)

int execve(char *fname, char *arg, char *envp)

int execvp(char *fname, char *arg)

int execvpe(char *fname, char *arg, char *envp)

Περιγραφή:

Αυτές οι λειτουργίες δεν ορίζονται από το πρότυπο ANSI C. Ομάδα λειτουργιώνεκτελεστ

χρησιμοποιείται για την εκτέλεση άλλου προγράμματος. Αυτό το άλλο πρόγραμμα, που ονομάζεται θυγατρική διεργασία, φορτώνεται πάνω από το πρόγραμμα που περιέχει την κλήση exec. Το όνομα του αρχείου που περιέχει τη θυγατρική διεργασία καθορίζεται χρησιμοποιώντας την παράμετρο fname. Τυχόν ορίσματα που διαβιβάζονται στη θυγατρική διεργασία καθορίζονται είτε από τις παραμέτρους arg0 έως argN είτε από τον πίνακα arg. Η παράμετρος envp πρέπει να δείχνει στη συμβολοσειρά περιβάλλοντος. (Επιχειρήματα που επισημαίνονται από τον argv στη διαδικασία του παιδιού.) Εάν το fname δεν περιέχει επέκταση ή τελεία, η αναζήτηση εκτελείται πρώτα από το όνομα του αρχείου. Εάν δεν είναι επιτυχής, προστίθεται η επέκταση EXE και η αναζήτηση επαναλαμβάνεται. Εάν δεν είναι επιτυχής, χρησιμοποιείται η επέκταση COM και η αναζήτηση επαναλαμβάνεται ξανά. Εάν έχει καθοριστεί η επέκταση, τότε η αναζήτηση πραγματοποιείται μόνο για το θέμαακριβής αντιστοιχία

. Τέλος, εάν υπάρχει περίοδος, αλλά δεν έχει καθοριστεί επέκταση, τότε η αναζήτηση πραγματοποιείται στην αριστερή πλευρά του ονόματος του αρχείου.

Ο ακριβής τρόπος με τον οποίο εκτελείται μια θυγατρική διεργασία εξαρτάται από την έκδοση της συνάρτησης exec που καλείται. Μπορείτε να σκεφτείτε ότι η συνάρτηση exec έχει διάφορα επιθήματα που καθορίζουν τις λειτουργίες της. Το επίθημα μπορεί να αποτελείται από έναν ή δύο χαρακτήρες.

Εάν καθοριστεί το επίθημα l, σημαίνει ότι τα ορίσματα μεταβιβάζονται στη θυγατρική διαδικασία μεμονωμένα, αντί σε πίνακα. Αυτή η μέθοδος χρησιμοποιείται κατά τη μετάδοση ενός σταθερού αριθμού ορισμάτων. Λάβετε υπόψη ότι το τελευταίο όρισμα πρέπει να είναι NULL. (NULL ορίζεται στο stdio.h.)

Το επίθημα v σημαίνει ότι τα ορίσματα μεταβιβάζονται στη θυγατρική διαδικασία σε έναν πίνακα. Αυτή η μέθοδος χρησιμοποιείται όταν δεν είναι γνωστό εκ των προτέρων πόσα ορίσματα θα περάσουν στη θυγατρική διεργασία ή ο αριθμός των ορισμάτων μπορεί να αλλάξει κατά την εκτέλεση του προγράμματος. Συνήθως το τέλος ενός πίνακα υποδεικνύεται με έναν μηδενικό δείκτη.

Το επίθημα e υποδεικνύει ότι μία ή περισσότερες συμβολοσειρές περιβάλλοντος θα περάσουν στη θυγατρική διαδικασία. Η παράμετρος envp είναι ένας πίνακας δεικτών σε συμβολοσειρές. Κάθε γραμμή που δείχνει ο πίνακας πρέπει να μοιάζει με αυτό: περιβάλλον_μεταβλητή = τιμή

Ο τελευταίος δείκτης στον πίνακα πρέπει να είναι NULL. Εάν το πρώτο στοιχείο του πίνακα είναι NULL, τότε η θυγατρική διαδικασία διατηρεί το ίδιο περιβάλλον με τη διεργασία προγονικού.

Είναι σημαντικό να θυμάστε ότι τα αρχεία που ανοίγονται από το exec είναι επίσης ανοιχτά στο θυγατρικό πρόγραμμα.

Εάν είναι επιτυχής, το exec δεν επιστρέφει τιμή. Σε περίπτωση αποτυχίας, το -1 επιστρέφεται και το errno ορίζεται σε μία από τις ακόλουθες τιμές:

Πρώτα από παρακάτω προγράμματακαλεί το δεύτερο, το οποίο εκτυπώνει τα επιχειρήματά του. Σημειώστε ότι και τα δύο προγράμματα πρέπει να είναι in ξεχωριστά αρχεία.

/* το πρώτο αρχείο είναι γονικό */
#περιλαμβάνω
#περιλαμβάνω
#περιλαμβάνω
int main (κενό)
{
execl("test.exe" , "test.exe" , "hello" , "10" , NULL);
επιστροφή 0 ;
}

/* το δεύτερο αρχείο είναι παιδί */
#περιλαμβάνω
#περιλαμβάνω
int main(int argc, char * argv)
{
printf( "Αυτό το πρόγραμμα εκτελείται με αυτές τις εντολές") ;
printf ("επιχειρήματα: " );
printf (argv[ 1 ] ) ;
printf (" %d" , atoi (argv[ 2 ] ) ;
επιστροφή 0 ;
}

Ανάλυση κύκλος ζωήςδρομολογήθηκε διαδικασία λειτουργικό σύστημα UNIX

Μία από τις πολλές ευθύνες ενός διαχειριστή συστήματος είναι να διασφαλίσει ότι τα προγράμματα των χρηστών ξεκινούν σωστά. Αυτή η εργασία περιπλέκεται από την παρουσία άλλων προγραμμάτων που εκτελούνται ταυτόχρονα στο σύστημα. Με ποικίλοι λόγοιαυτά τα προγράμματα ενδέχεται να μην λειτουργούν, να παγώνουν ή να είναι ελαττωματικά. Η κατανόηση της διαδικασίας δημιουργίας, διαχείρισης και καταστροφής αυτών των θέσεων εργασίας στο λειτουργικό σύστημα UNIX® είναι το πιο σημαντικό βήμαγια τη δημιουργία ενός πιο αξιόπιστου συστήματος.

Οι προγραμματιστές μελετούν τον τρόπο με τον οποίο ο πυρήνας διαχειρίζεται τις διεργασίες επίσης επειδή οι εφαρμογές που λειτουργούν καλά με άλλα μέρη του συστήματος απαιτούν λιγότερους πόρους και είναι λιγότερο πιθανό να προκαλέσουν προβλήματα στο σύστημα. διαχειριστές συστήματος. Μια εφαρμογή που χρειάζεται συνεχώς επανεκκίνηση επειδή δημιουργεί διαδικασίες ζόμπι (που περιγράφονται παρακάτω) είναι φυσικά μη επιθυμητή. Κατανόηση συστήματα UNIXσημαίνει ότι οι διαχειριζόμενες διαδικασίες επιτρέπουν στους προγραμματιστές να δημιουργούν προγράμματα που εκτελούνται ομαλά Ιστορικό. Δεν χρειάζεται να εμφανίζεται μια συνεδρία τερματικού στην οθόνη κάποιου.

Το κύριο δομικό στοιχείο ελέγχου αυτών των προγραμμάτων είναι η διαδικασία. Μια διεργασία είναι το όνομα που δίνεται σε ένα πρόγραμμα που εκτελείται από το λειτουργικό σύστημα. Εάν γνωρίζετε την εντολή ps, θα πρέπει να είστε εξοικειωμένοι με μια λίστα διεργασιών όπως αυτή στο .

Καταχώριση 1. Έξοδος της εντολής ps
sunbox#ps -ef UID PID PPID C STIME TTY TIME CMD root 0 0 0 20:15:23 ? 0:14 sched root 1 0 0 20:15:24 ? 0:00 /sbin/init root 2 0 0 20:15:24 ? 0:00 pageout root 3 0 0 20:15:24 ? 0:00 fsflush daemon 240 1 0 20:16:37 ? 0:00 /usr/lib/nfs/statd ...

Οι τρεις πρώτες στήλες είναι σημαντικές για εξέταση. Το πρώτο περιέχει μια λίστα χρηστών για λογαριασμό των οποίων εκτελούνται οι διεργασίες, το δεύτερο περιέχει τα αναγνωριστικά των διεργασιών και το τρίτο περιέχει τα αναγνωριστικά των γονικών διεργασιών. Η τελευταία στήλη περιέχει μια περιγραφή της διαδικασίας, συνήθως το όνομα τρέχον πρόγραμμα. Σε κάθε διεργασία εκχωρείται ένα αναγνωριστικό που ονομάζεται αναγνωριστικό διαδικασίας (PID). Μια διεργασία έχει επίσης έναν γονέα, στις περισσότερες περιπτώσεις υποδεικνύεται το PID της διαδικασίας που ξεκίνησε τη διαδικασία.

Η ύπαρξη ενός γονικού PID (PPID) σημαίνει ότι μια διεργασία δημιουργείται από μια άλλη διεργασία. Η αρχική διεργασία που ξεκινά στο σύστημα ονομάζεται init και της εκχωρείται πάντα PID 1. Το init είναι η πρώτη πραγματική διαδικασία που ξεκινά ο πυρήνας κατά την εκκίνηση. Το κύριο καθήκον του init είναι να ξεκινήσει ολόκληρο το σύστημα. Το init και άλλες διεργασίες με PPID 0 είναι διεργασίες πυρήνα.

Χρήση της κλήσης συστήματος διχάλας

Η κλήση συστήματος fork(2) δημιουργεί μια νέα διαδικασία. Το πιρούνι που χρησιμοποιείται φαίνεται στο απλό παράδειγμαΚωδικός C.

Λίστα 2. Απλή χρήση πιρουνιού(2)
sunbox$ cat fork1.c #include #περιλαμβάνω int main (void) ( pid_t p; /* fork επιστρέφει τύπος pid_t */ p = fork(); printf("fork επέστρεψε %d\n", p); ) sunbox$ gcc fork1.c -o fork1 sunbox$ . /fork1 πιρούνι επέστρεψε 0 πιρούνι επέστρεψε 698

Ο κώδικας στο fork1.c απλώς καλεί το fork και εμφανίζει το ακέραιο αποτέλεσμα της εκτέλεσης του fork μέσω μιας κλήσης printf. Πραγματοποιείται μόνο μία κλήση, αλλά η έξοδος εμφανίζεται δύο φορές. Αυτό συμβαίνει επειδή δημιουργείται μια νέα διαδικασία μέσα πιρούνι κλήσης. Μετά την κλήση, επιστρέφουν δύο ξεχωριστές διαδικασίες. Αυτό ονομάζεται συχνά "κλήθηκε μία φορά, επέστρεψε δύο φορές".

Οι τιμές επιστροφής από το πιρούνι είναι πολύ ενδιαφέρουσες. Ένα από αυτά είναι 0. η άλλη είναι μια μη μηδενική τιμή. Η διαδικασία που λαμβάνει 0 ονομάζεται που δημιουργείται από τη διαδικασία, και η μη μηδενική τιμή πηγαίνει στην αρχική διαδικασία, η οποία είναι γονική διαδικασία. Χρησιμοποιείτε τις επιστρεφόμενες τιμές για να προσδιορίσετε ποια διαδικασία είναι ποια. Δεδομένου ότι και οι δύο διεργασίες συνεχίζουν την εκτέλεση στην ίδια περιοχή, ο μόνος πιθανός διαφοροποιητής είναι οι τιμές επιστροφής του fork.

Η λογική για μια μηδενική και μη μηδενική επιστρεφόμενη τιμή είναι ότι μια θυγατρική διαδικασία μπορεί πάντα να βρει τον γονέα της χρησιμοποιώντας ένα αίτημα getppid(2), αλλά είναι πολύ πιο δύσκολο για έναν γονέα να προσδιορίσει όλα τα παιδιά του. Με αυτόν τον τρόπο, ο γονιός μαθαίνει για το νέο του παιδί και το παιδί μπορεί να βρει τον γονέα του αν χρειαστεί.

Τώρα, γνωρίζοντας την τιμή επιστροφής του fork , ο κώδικας μπορεί να διακρίνει μεταξύ των διεργασιών θυγατρικού και γονέα και να συμπεριφέρεται ανάλογα. Το B δείχνει ένα πρόγραμμα που εμφανίζεται διαφορετικά συμπεράσματα, με βάση τα αποτελέσματα του πιρουνιού .

Λίστα 3. Περισσότερα πλήρες παράδειγμα χρησιμοποιώντας πιρούνι
sunbox$ cat fork2.c #include #περιλαμβάνω int main (void) ( pid_t p; printf("Αρχικό πρόγραμμα, pid=%d\n", getpid()); p = fork(); if (p == 0) ( printf("Σε θυγατρική διαδικασία, pid =%d, ppid=%d\n", getpid(), getppid()); ) else ( printf("Σε γονικό, pid=%d, fork returned=%d\n", getpid(), p) ;
Λίστα 6. Η διαδικασία γονέα πεθαίνει πριν το παιδί
#περιλαμβάνω #περιλαμβάνω int main(void) ( int i; if (fork()) ( /* Parent */ sleep(2); _exit(0); ) for (i=0; i< 5; i++) { printf("My parent is %d\n", getppid()); sleep(1); } } sunbox$ gcc die1.c -o die1 sunbox$ ./die1 My parent is 2920 My parent is 2920 sunbox$ My parent is 1 My parent is 1 My parent is 1

Σε αυτό το παράδειγμα, η γονική διαδικασία καλεί το fork, περιμένει δύο δευτερόλεπτα και βγαίνει. Η θυγατρική διαδικασία συνεχίζεται, εκτυπώνοντας το PID του γονέα του για πέντε δευτερόλεπτα. Μπορείτε να δείτε ότι όταν ο γονέας πεθαίνει, το PPID αλλάζει σε 1. Επίσης ενδιαφέρουσα είναι η επιστροφή του ελέγχου επεξεργαστής εντολών. Επειδή η θυγατρική διαδικασία εκτελείται στο παρασκήνιο, μόλις πεθάνει ο γονέας, ο έλεγχος επιστρέφει στο κέλυφος.

Το παιδί πεθαίνει πριν από τον γονιό

Περιγράφει την αντίθετη διαδικασία: τον θάνατο ενός απόγονου ενώπιον του γονέα. Για να δείξετε καλύτερα τι συμβαίνει, τίποτα δεν εκτυπώνεται απευθείας από τη διαδικασία. Αντί για αυτό, ενδιαφέρουσες πληροφορίεςβρίσκεται στη λίστα διαδικασιών.

Λίστα 7. Η θυγατρική διαδικασία πεθαίνει πριν από τη γονική διαδικασία
sunbox$ cat die2.c #include #περιλαμβάνω int main(void) ( int i; if (!fork()) ( /* Το παιδί βγαίνει αμέσως*/ _exit(0); ) /* Ο γονέας περιμένει περίπου ένα λεπτό */ sleep(60); ) sunbox$ gcc die2. c -o die2 sunbox$ ./die2 & 2934 sunbox$ ps -ef | grep 2934 sean 2934 2885 0 21:43:05 pts/1 0:00 ./die2 sean 2935 2934 0 - ? 0:00 sunbox$ ps -ef | grep 2934 + Έξοδος 199 ./die2

Το die2 εκτελείται στο παρασκήνιο χρησιμοποιώντας τον τελεστή & και, στη συνέχεια, εμφανίζει μια λίστα διεργασιών, που δείχνει μόνο τη διαδικασία που εκτελείται και τα παιδιά της. Το PID 2934 είναι η γονική διαδικασία, το PID 2935 είναι η διαδικασία που δημιουργείται και τερματίζεται αμέσως. Παρά την πρόωρη έξοδο, η αναπαραγωγική διαδικασία εξακολουθεί να βρίσκεται στον πίνακα διεργασιών, ήδη όπως νεκρόςμια διαδικασία που ονομάζεται επίσης βρυκόλακας. Όταν ο γονέας πεθάνει μετά από 60 δευτερόλεπτα, και οι δύο διαδικασίες τερματίζονται.

Όταν μια θυγατρική διεργασία πεθαίνει, ο γονέας της ενημερώνεται χρησιμοποιώντας ένα σήμα που ονομάζεται SIGCHLD. Ο ακριβής μηχανισμός όλων αυτών δεν έχει σημασία τώρα. Αυτό που πραγματικά έχει σημασία είναι ότι ο γονιός πρέπει με κάποιο τρόπο να γνωρίζει για το θάνατο του παιδιού. Από τη στιγμή που το παιδί πεθαίνει έως ότου ο γονέας λάβει το σήμα, το παιδί βρίσκεται σε κατάσταση ζόμπι. Το ζόμπι δεν εκτελείται και δεν καταναλώνει πόρους CPU. καταλαμβάνει χώρο μόνο στον πίνακα διεργασιών. Όταν ο γονέας πεθάνει, ο πυρήνας μπορεί τελικά να αφαιρέσει τα παιδιά μαζί με τον γονέα. Που σημαίνει, ο μόνος τρόποςΤο να απαλλαγείς από ένα ζόμπι σκοτώνεις έναν γονέα. Ο καλύτερος τρόποςαντιμετωπίστε τα ζόμπι - διασφαλίζοντας ότι δεν θα βγουν στην κορυφή. Ο κωδικός Β περιγράφει έναν χειριστή σήματος για τον χειρισμό του εισερχόμενου σήματος SIGCHLD.

Λίστα 8. Χειριστής σήματος σε δράση
#περιλαμβάνω #περιλαμβάνω #περιλαμβάνω #περιλαμβάνω void sighandler(int sig) ( printf("Int signal handler for signal %d\n", sig); /* wait() είναι το κύριο για την επιβεβαίωση SIGCHLD */ wait(0); ) int main(void) ( int i ; /* Ρυθμίστε το πρόγραμμα χειρισμού σήματος σε SIGCHLD */ sigset(SIGCHLD, &sighandler if (!fork()) ( /* Descendant */ _exit(0); ) sleep(60); & 3116 sunbox$ Χειριστής σήματος In για σήμα 18 ps -ef | grep 3116 sean 3116 2885 0 22:37:26 pts/1 0:00 ./die3

Λίγο πιο περίπλοκο από το προηγούμενο παράδειγμα, επειδή υπάρχει μια συνάρτηση sigset που ορίζει τον δείκτη συνάρτησης στον χειριστή σήματος. Κάθε φορά που μια διεργασία λαμβάνει ένα επεξεργασμένο σήμα, καλείται η συνάρτηση που καθορίζεται μέσω του sigset. Για ένα σήμα SIGCHLD, η εφαρμογή πρέπει να καλέσει την αναμονή (3c) για να περιμένει να τερματιστεί η θυγατρική διαδικασία. Εφόσον η διαδικασία έχει ήδη ολοκληρωθεί, αυτό είναι απαραίτητο για να λάβει ο πυρήνας επιβεβαίωση ότι τα παιδιά έχουν πεθάνει. Στην πραγματικότητα, ο γονέας πρέπει να κάνει περισσότερα από το να αναγνωρίσει απλώς το σήμα. Θα πρέπει επίσης να καθαρίσει τα δεδομένα του παιδιού.

Μετά την εκτέλεση του die3, ελέγχεται η λίστα των διεργασιών. Ο χειριστής σήματος λαμβάνει την τιμή 18 (SIGCHLD), γίνεται η επιβεβαίωση ολοκλήρωσης του παιδιού και ο γονέας επιστρέφει στην κατάσταση ύπνου(60).

Σύντομα συμπεράσματα

Οι διεργασίες UNIX δημιουργούνται όταν μια διεργασία καλεί ένα fork, το οποίο χωρίζει τη διεργασία που εκτελείται σε δύο. Στη συνέχεια, η διαδικασία μπορεί να εκτελέσει μία από τις κλήσεις συστήματος στην οικογένεια exec, η οποία αντικαθιστά την τρέχουσα εικόνα με μια νέα.

Όταν μια γονική διαδικασία πεθαίνει, όλα τα παιδιά της υιοθετούνται από το init , το οποίο έχει PID 1. Εάν ένα παιδί πεθάνει πριν από τον γονέα, ένα σήμα περνά στη γονική διαδικασία και το παιδί μεταβαίνει σε κατάσταση ζόμπι μέχρι το σήμα αναγνωρίζεται ή η γονική διαδικασία σκοτώνεται.

Τώρα που γνωρίζετε πώς δημιουργούνται και καταστρέφονται οι διεργασίες, θα είναι ευκολότερο για εσάς να κατανοήσετε τις διεργασίες που εκτελούνται στο σύστημά σας. Αυτό ισχύει ιδιαίτερα για διαδικασίες με πολύπλοκη δομή, οι οποίες περιπλέκονται από πολλές άλλες διεργασίες όπως το Apache. Η ικανότητα εντοπισμού του δέντρου διεργασίας για ορισμένους χωριστή διαδικασία, σας επιτρέπει να εντοπίσετε οποιαδήποτε εφαρμογή πίσω στη διαδικασία



Έχετε ερωτήσεις;

Αναφέρετε ένα τυπογραφικό λάθος

Κείμενο που θα σταλεί στους συντάκτες μας: