2010-04-25 6 views
27

Ho bisogno di utilizzare le funzioni fork() e wait() per completare un compito. Stiamo modellando un comportamento non deterministico e abbiamo bisogno che il programma si biforchi() se c'è più di una possibile transizione.fork() e wait() con due processi figlio

Per cercare di capire come funziona la forchetta e attendere, ho appena creato un programma semplice. Penso di capire ora come funzionano le chiamate e andrebbe bene se il programma si diramasse solo una volta perché il processo genitore potrebbe utilizzare lo stato di uscita dal processo figlio singolo per determinare se il processo figlio ha raggiunto o meno lo stato di accettazione.

Come si può vedere dal codice che segue, tuttavia, voglio essere in grado di gestire le situazioni in cui devono essere presenti più processi figlio. Il mio problema è che sembra che tu sia in grado di impostare lo stato solo usando una funzione _exit una volta. Pertanto, come nel mio esempio, lo stato di uscita verificato dal processo padre per indica che il primo processo figlio ha emesso 0 come stato di uscita, ma non ha informazioni sul secondo processo figlio.

Ho provato semplicemente non _exit() - su un rifiuto, ma poi quel processo figlio avrebbe continuato, e in effetti sembrerebbe che ci siano due processi genitore.

Ci scusiamo per la chiacchiera, ma sarei grato se qualcuno potesse dirmi come il mio processo genitore potrebbe ottenere le informazioni sullo stato su più di un processo figlio, o sarei felice per il processo genitore di notare solo accettare lo stato da il bambino elabora, ma in tal caso dovrei uscire con successo dai processi figli che hanno uno stato di rifiuto.

mio codice di prova è la seguente:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/wait.h> 

int main(void) { 

    pid_t child_pid, wpid, pid; 
    int status = 0; 
    int i; 

    int a[3] = {1, 2, 1}; 
    for(i = 1; i < 3; i++) { 
     printf("i = %d\n", i); 
     pid = getpid(); 
     printf("pid after i = %d\n", pid); 
     if((child_pid = fork()) == 0) { 
      printf("In child process\n"); 
      pid = getpid(); 
      printf("pid in child process is %d\n", pid); 
      /* Is a child process */ 
      if(a[i] < 2) { 
       printf("Should be accept\n"); 
       _exit(1); 
      } else { 
       printf("Should be reject\n"); 
       _exit(0); 
      } 
     } 
    } 

    if(child_pid > 0) { 
     /* Is the parent process */ 
     pid = getpid(); 
     printf("parent_pid = %d\n", pid); 
     wpid = wait(&status); 
     if(wpid != -1) { 
      printf("Child's exit status was %d\n", status); 
      if(status > 0) { 
       printf("Accept\n"); 
      } else { 
       printf("Complete parent process\n"); 
       if(a[0] < 2) { 
        printf("Accept\n"); 
       } else { 
        printf("Reject\n"); 
       } 
      } 
     } 
    } 
    return 0; 
} 

risposta

35

Mi sembra che il problema di base sia che si ha una chiamata wait() anziché un ciclo che attende fino a quando non ci sono più figli. Inoltre, si attende solo se l'ultimo fork() ha esito positivo anziché se almeno uno fork() ha esito positivo.

È necessario utilizzare solo _exit() se non si desidera eseguire normali operazioni di pulizia, ad esempio lo scarico di flussi di file aperti compreso stdout. Ci sono occasioni per usare _exit(); questo non è uno di loro. (In questo esempio, potresti anche semplicemente far tornare i figli invece di chiamare exit() direttamente perché il ritorno da main() equivale a uscire con lo stato restituito. Tuttavia, molto spesso si farebbe il biforcarsi e così via in un funzione diversa main(), e quindi exit() è spesso appropriata.)


Hacked, versione semplificata del codice che dà la diagnostica che vorrei. Si noti che il ciclo for ha saltato il primo elemento dell'array (il mio no).

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <sys/wait.h> 

int main(void) 
{ 
    pid_t child_pid, wpid; 
    int status = 0; 
    int i; 
    int a[3] = {1, 2, 1}; 

    printf("parent_pid = %d\n", getpid()); 
    for (i = 0; i < 3; i++) 
    { 
     printf("i = %d\n", i); 
     if ((child_pid = fork()) == 0) 
     { 
      printf("In child process (pid = %d)\n", getpid()); 
      if (a[i] < 2) 
      { 
       printf("Should be accept\n"); 
       exit(1); 
      } 
      else 
      { 
       printf("Should be reject\n"); 
       exit(0); 
      } 
      /*NOTREACHED*/ 
     } 
    } 

    while ((wpid = wait(&status)) > 0) 
    { 
     printf("Exit status of %d was %d (%s)\n", (int)wpid, status, 
       (status > 0) ? "accept" : "reject"); 
    } 
    return 0; 
} 

Esempio di output (MacOS X 10.6.3):

parent_pid = 15820 
i = 0 
i = 1 
In child process (pid = 15821) 
Should be accept 
i = 2 
In child process (pid = 15822) 
Should be reject 
In child process (pid = 15823) 
Should be accept 
Exit status of 15823 was 256 (accept) 
Exit status of 15822 was 0 (reject) 
Exit status of 15821 was 256 (accept) 
+0

Ok. Capisco. La ringrazio molto per la risposta. – Joe

+0

Grazie ancora per il tuo tempo. È fantastico. Ho prodotto una mia versione di lavoro alterata dopo il tuo post iniziale, ma la tua è molto più ordinata. Saluti – Joe

+0

@Giuttosto se questa risposta ti è stata di grande aiuto, dovresti accettarla facendo clic sul segno di spunta a sinistra. –

8

Metti la tua funzione di attesa() in un ciclo e attendere che tutti i processi figlio. La funzione wait restituirà -1 e errno sarà uguale a ECHILD se non sono disponibili altri processi figli.

+0

Grande. Capisco. Grazie mille. – Joe

1

esempio brillante Jonathan Leffler, per rendere il vostro lavoro codice su SLES, avevo bisogno di aggiungere un'intestazione aggiuntiva per consentire l'oggetto pid_t :)

#include <sys/types.h> 
+0

È molto strano ... POSIX 2008 e tutti gli altri sistemi Linux che ho incontrato non hanno bisogno dell'intestazione ''. Ci sono funzioni in '' (come 'getpid()') che richiedono il tipo nella loro dichiarazione, quindi '' non deve essere incluso esplicitamente. Puoi indicare le opzioni del compilatore che stavi utilizzando che è necessario '#include '? –

+0

@ JonathanLeffler So che è un vecchio commento, ma SLES è più vecchio del resto. È come l'EL di RedHat. Quindi questa è la ragione, credo. – Shiki