Изчакване на процеси в C

Четох документацията за wait() и waitpid() и все още съм малко объркан за това как работят (разбрах, че wait(&status) е еквивалентно на waitpid(-1, &status, 0);). По-долу са някои малки фрагменти от код, върху които работя. Моля, помогнете ми да разбера дали тези фрагменти са написани правилно и ако не, защо не.

Цел 1: Пожънете всички деца на зомбита.

int reapedPid;
do {
    reapedPid = waitpid(-1,NULL,WNOHANG);
} while (reapedPid > 0);

Това, което се опитвам да направя тук, е да претърся всички деца, да пожъна детето, ако е завършено, да го оставя да продължи, ако не е, и когато свършат децата, тогава reapedPid == -1 и цикълът излиза. Причината да съм объркан тук е, че не виждам как waitpid() трябва да знае кои деца вече са били проверени и кои не. Прави ли такава проверка? Или този подход няма да работи?

Цел 2: Изчакайте всички деца да завършат.

int pid;
do {
    pid = wait(NULL);
} while (pid != -1);

Тук не ме интересува какъв е резултатният статус на децата - това трябва просто да продължи да чака всеки дъщерен процес да завърши, независимо дали успешно или неуспешно, и след това да излезе. Мисля, че този код е правилен, но не съм сигурен.

Цел 3: Разклонете дете и изчакайте да завърши.

int pid = fork();
if (pid < 0) {
    // handle error.
}
else if (pid == 0) {
    // execute child command
}
else {
    int status;
    int waitedForPid = waitpid(pid,&status,0);
    assert(waitedForPid == pid);
}

Тук просто се опитвам да разклоня процеса и да накарам родителя да изчака детето да завърши. Не съм напълно сигурен дали трябва да предам опцията 0 тук, но изглежда, че WNOHANG, WUNTRACED и WCONTINUED не са наистина подходящи за моята цел.


person Kvass    schedule 19.11.2013    source източник


Отговори (2)


  1. Работата на ядрото е да следи процесите. Проследяването на мъртвите процеси е тривиално. Ядрото може да каже кои дъщерни процеси са умрели, но все още не са били изчакани, и ще връща едно от тези мъртви деца при всяко повикване, докато не останат други за докладване. (Поради опцията WNOHANG може все още да има деца, които да чакат, но нито едно от останалите деца все още не е мъртво.)

  2. Този втори цикъл също е добър и почти еквивалентен на първия. Разликата е, че ще виси, чакайки всички деца да умрат, преди да върне -1.

  3. Този трети фрагмент е добре; твърдението ще бъде вярно, освен при извънредни обстоятелства (като друга нишка в програмата също е изчакала детето и е прибрала трупа). Въпреки това, ако някъде сте стартирали друг процес и сте го оставили да работи във фонов режим, може да събирате зомбита, докато с модификация на другите цикли можете да събирате зомбитата и пак да чакате правилното дете:

    int pid = fork();
    
    if (pid < 0)
    {
        // handle error.
    }
    else if (pid == 0)
    {
        // execute child command
    }
    else
    {
        int status;
        int corpse;
        while ((corpse = waitpid(-1, &status, 0)) > 0)
            if (corpse == pid)
                break;
    }
    
person Jonathan Leffler    schedule 19.11.2013
comment
Цикълът, който предоставихте за #3, е интересно средство за многозадачност. Що се отнася до #2, казахте, че е еквивалентно на #1, но аз се опитвам да постигна две различни цели в тези случаи - тогава #2 грешно ли е? Във втория случай искам да изчакам всичко да приключи, зомбирано или не. В първия не искам наистина да забавям, просто да пожъна каквото мога и след това да продължа напред. - person Kvass; 19.11.2013
comment
Прав си; Не обърнах достатъчно внимание на опциите в първия цикъл. Актуализирах отговора си; твоето разбиране е доста на място. Ако кодирате обвивка, можете да позволите на потребителите да изпълняват задачи във фонов режим (&?); тогава цикълът, който показвам, става важен - въпреки че вероятно бихте искали да запишете смъртта на отделните деца (например, за да можете да уведомите потребителя, че техните фонови задачи са свършени), или за да можете да управлявате изходните статуси на всяка команда в тръбопровод или... - person Jonathan Leffler; 19.11.2013

За повечето от тях трябва да можете лесно да кодирате някои примерни програми и да проверите разбирането си.

Цел 1: Пожънете всички деца на зомбита.

Причината да съм объркан тук е, че не виждам как waitpid() трябва да знае кои деца вече са били проверени и кои не. Прави ли такава проверка?

След като дете излезе, то може да бъде waited само веднъж. Така че вашият цикъл ще получи статус на изход само за дъщерни процеси, които все още не са били waited (зомбита).

За Цели 2 и 3 отново бих сметнал за задължително упражнение да кодирате пример, за да видите как работи. За #2 вместо това бих предложил вашият код винаги да следи всички разклонени деца, така че да може да знае точно към кого да wait. Вашият код за #3 изглежда добре; не се изискват options. Не забравяйте да използвате макросите WEXITSTATUS и приятели, за да получите информация от status.

Вижте също:

person Jonathon Reinhart    schedule 19.11.2013
comment
В случай, че не мога да проследя всички разклонени деца (поради определени ограничения в спецификациите), #2 жизнеспособна опция ли е? - person Kvass; 19.11.2013
comment
@Kvass Вярвам, да. Но бих кодирал нещо малко и ще се уверя. - person Jonathon Reinhart; 19.11.2013
comment
Добре. Също така, трябва ли твърдението в моя пример 3 винаги да е вярно? - person Kvass; 19.11.2013