fork () и wait () с двумя дочерними процессами

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

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

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

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

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

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

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

person Joe    schedule 25.04.2010    source источник


Ответы (3)


Мне кажется, что основная проблема заключается в том, что у вас есть один вызов 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)
person Jonathan Leffler    schedule 25.04.2010
comment
В порядке. Я понимаю. Спасибо вам большое за ваш ответ. - person Joe; 25.04.2010
comment
Еще раз спасибо за ваше время. Замечательно. После вашего первого поста я создал свою искореженную рабочую версию, но ваша намного лучше. Ваше здоровье - person Joe; 25.04.2010
comment
@Joe, если этот ответ был для вас наиболее полезным, вы должны принять его, щелкнув галочку слева. - person Tyler McHenry; 25.04.2010
comment
@Richard: Я думал об этом, но поскольку в вопросе говорится, что это сокращенный пример для разборки деталей синхронизации между процессами, я пришел к выводу, что это не было ложным ответом на домашнее задание. - person Jonathan Leffler; 25.04.2010
comment
@Jonathan: Я просто пошутил ... Это был хороший вопрос, и ваш хороший ответ. - person Richard Pennington; 25.04.2010

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

person Richard Pennington    schedule 25.04.2010
comment
Здорово. Я понимаю. Большое спасибо. - person Joe; 25.04.2010

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

#include <sys/types.h>
person Rupert Bailey    schedule 04.02.2013
comment
Это очень странно ... POSIX 2008 и все другие системы Linux, с которыми я сталкивался, не нуждаются в заголовке <sys/types.h>. В <unistd.h> есть функции (например, getpid()), для которых в объявлении требуется тип, поэтому <sys/types.h> не нужно включать явно. Можете ли вы указать параметры компилятора, которые вы использовали для #include <sys/types.h>? - person Jonathan Leffler; 10.02.2013
comment
@JonathanLeffler Я знаю, что это старый комментарий, но SLES старше остальных. Это как EL RedHat. Думаю, в этом причина. - person Apache; 13.05.2013