2010-04-25 8 views
27

Je dois utiliser les fonctions fork() et wait() pour terminer une assignation. Nous modélisons un comportement non-déterministe et avons besoin du programme fork() s'il y a plus d'une transition possible.fork() et wait() avec deux processus fils

Afin d'essayer de comprendre comment fonctionne la fourche et d'attendre, je viens de faire un programme simple. Je pense que je comprends maintenant comment fonctionnent les appels et que ça irait si le programme ne se ramifiait qu'une seule fois car le processus parent pouvait utiliser le statut de sortie du processus fils unique pour déterminer si le processus fils atteignait ou non l'état d'acceptation.

Comme vous pouvez le voir dans le code qui suit, je veux être capable de gérer des situations où il doit y avoir plus d'un processus fils. Mon problème est que vous semblez être en mesure de définir le statut en utilisant une seule fois la fonction _exit. Ainsi, comme dans mon exemple, le statut de sortie pour lequel le processus parent effectue des tests montre que le premier processus enfant a émis 0 comme statut de sortie, mais n'a aucune information sur le second processus enfant.

J'ai simplement essayé de ne pas exécuter _exit() sur un rejet, mais alors ce processus fils continuerait, et en fait il semblerait qu'il y ait deux processus parents.

Désolé pour la gaufre, mais je serais reconnaissant si quelqu'un pouvait me dire comment mon processus parent pourrait obtenir les informations d'état sur plus d'un processus enfant, ou je serais heureux que le processus parent remarque uniquement l'acceptation des statuts l'enfant traite, mais dans ce cas, j'aurais besoin de quitter les processus fils qui ont un statut de rejet.

Mon code de test est la suivante:

#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; 
} 

Répondre

35

Il me semble que le problème de base est que vous avez un appel wait() plutôt qu'une boucle qui attend qu'il n'y ait plus d'enfants. Vous attendez également seulement si la dernière fork() est réussie plutôt que si au moins un fork() réussit.

Vous ne devez utiliser _exit() que si vous ne voulez pas d'opérations de nettoyage normales, telles que le vidage des flux de fichiers ouverts, y compris stdout. Il y a des occasions d'utiliser _exit(); Ce n'est pas l'un d'eux. (Dans cet exemple, vous pouvez également, bien sûr, simplement renvoyer les enfants au lieu d'appeler exit() directement, car le retour de main() revient à quitter le statut renvoyé, mais le plus souvent, vous feriez le forking, et ainsi de suite. autre fonction que main(), puis exit() est souvent le cas.)


Hacked, version simplifiée de votre code qui donne le diagnostic que je veux. Notez que votre boucle for a ignoré le premier élément du tableau (le mien ne le fait pas).

#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; 
} 

Exemple de sortie (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. Je comprends. Merci beaucoup pour votre réponse. – Joe

+0

Merci encore pour votre temps. C'est génial. J'ai produit une version de travail mutilée après votre premier message, mais la vôtre est beaucoup plus propre. Cheers – Joe

+0

@Joe si cette réponse vous a été la plus utile, vous devez l'accepter en cliquant sur la coche à gauche. –

8

Mettez votre fonction wait() dans une boucle et d'attendre que tous les processus enfants. La fonction wait retournera -1 et errno sera égal à ECHILD s'il n'y a plus de processus fils disponibles.

+0

Grand. Je comprends. Merci beaucoup. – Joe

1

brillant exemple Jonathan Leffler, pour faire votre travail de code sur SLES, je besoin d'ajouter un en-tête supplémentaire pour permettre à l'objet pid_t :)

#include <sys/types.h> 
+0

C'est très étrange ... POSIX 2008 et tous les autres systèmes Linux que j'ai rencontrés n'ont pas besoin de l'en-tête ''. Il y a des fonctions dans '' (comme 'getpid()') qui requièrent le type dans leur déclaration, donc '' n'a pas besoin d'être inclus explicitement. Pouvez-vous indiquer les options du compilateur que vous utilisiez qui nécessitaient '#include '? –

+0

@JonathanLeffler Je sais que c'est un vieux commentaire, mais SLES est plus vieux que le reste. C'est comme EL de RedHat. Donc c'est la raison pour laquelle je suppose. – Shiki

Questions connexes