Подтвердить что ты не робот

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

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

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

Как вы можете видеть из приведенного ниже кода, я хочу иметь возможность обрабатывать ситуации, когда должно быть несколько дочерних процессов. Моя проблема заключается в том, что вы, похоже, можете установить статус только с помощью функции _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 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;
}
4b9b3361

Ответ 1

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

Вы должны использовать только _exit(), если вам не нужны обычные операции очистки, такие как очистка открытых файловых потоков, включая stdout. Бывают случаи использования _exit(); Это не один из них. (В этом примере вы также можете, конечно, просто вернуть детей вместо прямого вызова exit(), потому что возврат из main() эквивалентен завершению с возвращенным статусом. Однако чаще всего вы будете использовать forking и поэтому в функции, отличной от 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)

Ответ 2

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

Ответ 3

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

#include <sys/types.h>