linux – sleep () del processo padre interrotto dal processo figlio

Quando un processo figlio è fork() ed, il processo genitore può wait() per il completamento del processo figlio. Supponiamo, solo per sperimentare, invece di wait() , se facciamo il processo genitore sleep() , allora perché non funziona?

 #include  #include  #include  int main() { pid_t child_id ; child_id = fork() ; if (child_id == 0) { printf("\nChild process"); printf("\nChild process exiting"); } else { printf("\nParent process"); sleep(10); printf("\nParent process exiting"); } } 

Immagino che il segnale SIGCHLD stia facendo sì che il processo genitore si riattivi da sleep() . Ma perché, è un processo figlio, hanno differenti spazi di indirizzamento e risorse, quindi come può interferire nelle questioni del processo genitore?

Fai attenzione alle differenze tra i sistemi. Con questo adattamento minore del tuo codice, eseguito su Mac OS X 10.9, il bambino che muore non influisce sul sleep(10) nel genitore:

 Parent process Child process Child process exiting 1384590368 Parent process exiting 1384590378 

Come puoi vedere, il genitore è uscito 10 secondi più tardi rispetto a quello del bambino.

 #include  #include  #include  int main(void) { pid_t child_id; child_id = fork(); if (child_id == 0) { printf("\nChild process"); printf("\nChild process exiting %ld\n", (long)time(0)); } else { printf("\nParent process\n"); sleep(10); printf("\nParent process exiting %ld\n", (long)time(0)); } } 

Ho avuto lo stesso comportamento su una VM che esegue un’antica versione di Linux (kernel 2.6.16.60 del 2008); il genitore è morto 10 secondi dopo il bambino.

Quindi, se il comportamento che stai chiedendo “perché non funziona?” è “il genitore esce immediatamente figlio muore”, quindi il tuo codice non dimostra che esce su uno dei due sistemi. Non posso dire categoricamente che il genitore non muoia prontamente sul tuo sistema, ma sarebbe inaspettato.

Potresti trovare questo programma utile per studiare il comportamento dei segnali SIGCHLD:

 #include  #include  #include  #include  #include  #include  #include  static siginfo_t sig_info; static volatile sig_atomic_t sig_num; static void *sig_ctxt; static void catcher(int signum, siginfo_t *info, void *vp) { sig_num = signum; sig_info = *info; sig_ctxt = vp; } static void set_handler(int signum) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = catcher; sigemptyset(&sa.sa_mask); if (sigaction(signum, &sa, 0) != 0) { int errnum = errno; fprintf(stderr, "Failed to set signal handler (%d: %s)\n", errnum, strerror(errnum)); exit(1); } } static void prt_interrupt(FILE *fp) { if (sig_num != 0) { fprintf(fp, "Signal %d from PID %d\n", sig_info.si_signo, (int)sig_info.si_pid); sig_num = 0; } } static void five_kids(void) { for (int i = 0; i < 5; i++) { pid_t pid = fork(); if (pid < 0) break; else if (pid == 0) { printf("PID %d - exiting with status %d\n", (int)getpid(), i); exit(i); } else { int status = 0; pid_t corpse = wait(&status); printf("Child: %d; Corpse: %d; Status = 0x%.4X\n", pid, corpse, (status & 0xFFFF)); prt_interrupt(stdout); fflush(0); } } } int main(void) { printf("SIGCHLD set to SIG_DFL\n"); signal(SIGCHLD, SIG_DFL); five_kids(); printf("SIGCHLD set to SIG_IGN\n"); signal(SIGCHLD, SIG_IGN); five_kids(); printf("SIGCHLD set to catcher()\n"); set_handler(SIGCHLD); five_kids(); return(0); } 

Di nuovo su Mac OS X 10.9, ha prodotto:

 SIGCHLD set to SIG_DFL PID 52345 - exiting with status 0 Child: 52345; Corpse: 52345; Status = 0x0000 PID 52346 - exiting with status 1 Child: 52346; Corpse: 52346; Status = 0x0100 PID 52347 - exiting with status 2 Child: 52347; Corpse: 52347; Status = 0x0200 PID 52348 - exiting with status 3 Child: 52348; Corpse: 52348; Status = 0x0300 PID 52349 - exiting with status 4 Child: 52349; Corpse: 52349; Status = 0x0400 SIGCHLD set to SIG_IGN PID 52350 - exiting with status 0 Child: 52350; Corpse: -1; Status = 0x0000 PID 52351 - exiting with status 1 Child: 52351; Corpse: -1; Status = 0x0000 PID 52352 - exiting with status 2 Child: 52352; Corpse: -1; Status = 0x0000 PID 52353 - exiting with status 3 Child: 52353; Corpse: -1; Status = 0x0000 PID 52354 - exiting with status 4 Child: 52354; Corpse: -1; Status = 0x0000 SIGCHLD set to catcher() PID 52355 - exiting with status 0 Child: 52355; Corpse: -1; Status = 0x0000 Signal 20 from PID 52355 Child: 52356; Corpse: 52355; Status = 0x0000 PID 52356 - exiting with status 1 Child: 52357; Corpse: -1; Status = 0x0000 PID 52357 - exiting with status 2 Signal 20 from PID 52356 Child: 52358; Corpse: 52357; Status = 0x0200 Signal 20 from PID 52357 PID 52358 - exiting with status 3 Child: 52359; Corpse: 52356; Status = 0x0100 PID 52359 - exiting with status 4 

Il comportamento su Linux è simile - non del tutto identico:

 SIGCHLD set to SIG_DFL PID 14645 - exiting with status 0 Child: 14645; Corpse: 14645; Status = 0x0000 PID 14646 - exiting with status 1 Child: 14646; Corpse: 14646; Status = 0x0100 PID 14647 - exiting with status 2 Child: 14647; Corpse: 14647; Status = 0x0200 PID 14648 - exiting with status 3 Child: 14648; Corpse: 14648; Status = 0x0300 PID 14649 - exiting with status 4 Child: 14649; Corpse: 14649; Status = 0x0400 SIGCHLD set to SIG_IGN PID 14650 - exiting with status 0 Child: 14650; Corpse: -1; Status = 0x0000 PID 14651 - exiting with status 1 Child: 14651; Corpse: -1; Status = 0x0000 PID 14652 - exiting with status 2 Child: 14652; Corpse: -1; Status = 0x0000 PID 14653 - exiting with status 3 Child: 14653; Corpse: -1; Status = 0x0000 PID 14654 - exiting with status 4 Child: 14654; Corpse: -1; Status = 0x0000 SIGCHLD set to catcher() PID 14655 - exiting with status 0 Child: 14655; Corpse: 14655; Status = 0x0000 Signal 17 from PID 14655 PID 14656 - exiting with status 1 Child: 14656; Corpse: 14656; Status = 0x0100 Signal 17 from PID 14656 PID 14657 - exiting with status 2 Child: 14657; Corpse: 14657; Status = 0x0200 Signal 17 from PID 14657 PID 14658 - exiting with status 3 Child: 14658; Corpse: 14658; Status = 0x0300 Signal 17 from PID 14658 PID 14659 - exiting with status 4 Child: 14659; Corpse: 14659; Status = 0x0400 Signal 17 from PID 14659 

Per favore leggi attentamente le pagine man di fork (2) , execve (2) , wait (2) …

L’ wait syscall fa molto di più che attendere passivamente un processo figlio. Pulisce lo stato del kernel interno per evitare i processi di zombi .

Usa anche strace (1) ad esempio strace -f sul tuo programma.

E ci vogliono molte ore per leggere un buon libro come ad esempio Advanced Linux Programming . Capire i processi richiede molte ore e non abbiamo molto tempo per insegnartelo. Per favore, leggi i libri e continua a sperimentare come fai tu! Inoltre, prenditi del tempo per leggere il codice sorgente del software libero (come il codice sorgente di alcune shell -eg bash o sash )

BTW, il tuo programma è sbagliato su un altro punto: dovresti sempre verificare il fallimento del fork (quindi gestisci sempre i tre possibili ritorni del fork : ==0 nel processo figlio, >0 nel processo padre, <0 in caso di fallimento). Considerare l'utilizzo di ulimit (che chiama setrlimit (2) all'interno della shell) per triggersre tale condizione di errore a scopo di test.