web-dev-qa-db-fra.com

fork () et wait () avec deux processus enfants

J'ai besoin d'utiliser les fonctions fork () et wait () pour terminer une affectation. Nous modélisons un comportement non déterministe et avons besoin du programme à fork () s'il y a plus d'une transition possible.

Afin d'essayer de comprendre comment fonctionnent fork et wait, je viens de créer un programme simple. Je pense que je comprends maintenant comment les appels fonctionnent et ce serait bien si le programme ne se ramifiait qu'une seule fois parce que le processus parent pouvait utiliser le statut de sortie du processus enfant unique pour déterminer si le processus enfant avait atteint l'état d'acceptation ou non.

Comme vous pouvez le voir dans le code qui suit, je veux pouvoir gérer des situations où il doit y avoir plus d'un processus enfant. Mon problème est que vous ne semblez pouvoir définir l'état qu'une seule fois avec une fonction _exit. Ainsi, comme dans mon exemple, le statut de sortie que le processus parent teste montre que le premier processus enfant a émis 0 comme son statut de sortie, mais n'a aucune information sur le deuxième processus enfant.

J'ai simplement essayé de ne pas _exit () - sur un rejet, mais alors ce processus enfant 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 pouvait obtenir les informations de statut sur plus d'un processus enfant, ou je serais heureux que le processus parent ne remarque que l'acceptation du statut des processus enfants, mais dans ce cas, je devrais réussir à quitter les processus enfants qui ont un statut de rejet.

Mon code de test est le suivant:

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

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 uniquement si la dernière fork() réussit plutôt que si au moins une fork() réussit.

Vous ne devez utiliser _exit() que si vous ne voulez pas d'opérations de nettoyage normales, telles que le vidage de 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() équivaut à quitter avec le statut renvoyé. Cependant, la plupart des souvent, vous feriez la fourche et ainsi de suite dans une fonction autre que main(), puis exit() est souvent appropriée.)


Version piratée et simplifiée de votre code qui donne les diagnostics que je souhaiterais. Notez que votre boucle for a sauté le premier élément du tableau (pas le mien).

#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)
36
Jonathan Leffler

Mettez votre fonction wait () en boucle et attendez tous les processus enfants. La fonction d'attente renverra -1 et errno sera égal à ECHILD si plus aucun processus enfant n'est disponible.

9
Richard Pennington

exemple brillant Jonathan Leffler, pour faire fonctionner votre code sur SLES, j'avais besoin d'ajouter un en-tête supplémentaire pour autoriser l'objet pid_t :)

#include <sys/types.h>
1
Rupert Bailey