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