fork () и wait () с двумя дочерними процессами - PullRequest
27 голосов
/ 25 апреля 2010

Мне нужно использовать функции fork () и wait () для выполнения назначения. Мы моделируем недетерминированное поведение и нуждаемся в программе fork (), если существует более одного возможного перехода.

Чтобы попытаться понять, как работают fork и wait, я только что создал простую программу. Теперь я понимаю, как работают вызовы, и было бы хорошо, если бы программа разветвлялась только один раз, потому что родительский процесс мог использовать состояние выхода из одного дочернего процесса, чтобы определить, достиг ли дочерний процесс состояния принятия или нет.

Как вы можете видеть из следующего кода, я хочу иметь возможность обрабатывать ситуации, когда должно быть более одного дочернего процесса. Моя проблема в том, что вы, похоже, можете установить статус, используя функцию _exit только один раз. Итак, как и в моем примере, состояние выхода, которое проверяет родительский процесс, показывает, что первый дочерний процесс выдал 0 в качестве состояния выхода, но не имеет информации о втором дочернем процессе.

Я просто попытался не _exit () - при отклонении, но затем этот дочерний процесс продолжился бы, и в действительности, казалось бы, есть два родительских процесса.

Извините за вафлю, но я был бы признателен, если бы кто-то мог сказать мне, как мой родительский процесс мог получить информацию о состоянии более чем одного дочернего процесса, или я был бы рад, если родительский процесс только заметил, что статус принимается от дочерние процессы, но в этом случае мне нужно было бы успешно выйти из дочерних процессов, которые имеют статус отклонения.

Мой тестовый код выглядит следующим образом:

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

Ответы [ 3 ]

36 голосов
/ 25 апреля 2010

Мне кажется, что основная проблема в том, что у вас есть один вызов wait(), а не цикл, который ждет, пока не останется дочерних элементов. Вы также только ждете, если последний fork() будет успешным, а не если хотя бы один fork() будет успешным.

Вы должны использовать _exit(), только если вы не хотите выполнять обычные операции очистки, такие как очистка потоков открытых файлов, включая stdout. Есть случаи использования _exit(); Это не один из них. (В этом примере вы, конечно, могли бы просто заставить детей возвращаться вместо прямого вызова exit(), потому что возвращение из main() эквивалентно выходу с возвращенным состоянием. Однако чаще всего вы выполняете разветвление и так далее в функции, отличной от main(), и тогда exit() часто является подходящим.)


Взломанная, упрощенная версия вашего кода, которая дает необходимую диагностику. Обратите внимание, что ваш цикл for пропустил первый элемент массива (мой нет).

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

Пример вывода (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)
9 голосов
/ 25 апреля 2010

Поместите вашу функцию wait () в цикл и дождитесь всех дочерних процессов.Функция ожидания вернет -1 и значение errno будет равно ECHILD, если больше нет доступных дочерних процессов.

1 голос
/ 04 февраля 2013

блестящий пример Джонатан Леффлер, чтобы ваш код работал на SLES, мне нужно было добавить дополнительный заголовок, чтобы разрешить объект pid_t:)

#include <sys/types.h>
...