2009-10-02 14 views
12

W moim programie jestem rozwidleniem (równolegle) procesów potomnych w skończonej pętli while i wykonaniem exec na każdym z nich. Chcę, aby proces nadrzędny wznowił wykonywanie (punkt po tej pętli while) dopiero po zakończeniu wszystkich dzieci. Jak mam to zrobić?Oczekiwanie na wszystkie procesy potomne, zanim rodzic wznowi wykonywanie UNIX

Próbowałem kilku podejść. W jednym z podejść, zrobiłem parent pauzę po pętli while i wysłałem pewien warunek z obsługi SIGCHLD tylko wtedy, gdy waitpid zwrócił błąd ECHILD (żadne dziecko nie pozostało), ale problem, z jakim mam do czynienia w tym podejściu jest jeszcze zanim rodzic zakończył rozwidlanie wszystkich procesów, retStat staje się -1

void sigchld_handler(int signo) { 
     pid_t pid; 
     while((pid= waitpid(-1,NULL,WNOHANG)) > 0); 
     if(errno == ECHILD) { 
      retStat = -1; 
     } 
    } 

    **//parent process code** 
    retStat = 1; 
    while(some condition) { 
     do fork(and exec); 
    } 

    while(retStat > 0) 
     pause(); 
//This is the point where I want execution to resumed only when all children have finished 

Odpowiedz

21

Zamiast wywoływać waitpid w obsługi sygnału, to dlaczego nie stworzyć pętlę po tym, jak rozwidlony wszystkie procesy w następujący sposób:

while (pid = waitpid(-1, NULL, 0)) { 
    if (errno == ECHILD) { 
     break; 
    } 
} 

Program powinien zawisnąć w pętli, dopóki nie ma więcej dzieci. Wtedy wypadnie i program będzie kontynuowany. Dodatkowym bonusem będzie blokowanie na waitpid podczas gdy dzieci będą biegać, więc nie potrzebujesz pętli podczas oczekiwania.

Można również użyć wait(NULL), które powinny być równoważne z waitpid(-1, NULL, 0). Jeśli nie musisz robić nic więcej w SIGCHLD, możesz ustawić SIG_IGN.

+0

Muszę podać opcję WNOHANG, ponieważ jeśli istnieje wiele dzieci, które dostarczają sygnał SIGCHLD prawie w tym samym czasie, a ponieważ sygnały nie są umieszczane w kolejce w systemie UNIX, jeśli użyję 0, wtedy będę mógł złapać tylko jeden sygnał, wtedy zombie będą zostań w pobliżu. – avd

+0

Wystarczy dodać trochę, -1 sprawdzi przed każdym pid dziecka (może również używać WAIT_ANY dla jasności). – amischiefr

+0

@aditya: Procesy zombie czekają tylko na wywołanie wait() (lub wait_pid()) na nich. Jak tylko to zrobisz, znikną, niezależnie od tego, czy złapałeś sygnał. Tak więc pętla wait() po pętli fork() usunie wszystkie zombie. –

0

Myślę, że powinieneś użyć wywołania waitpid(). To pozwala czekać na "dowolny proces potomny", więc jeśli zrobisz to odpowiednią liczbę razy, powinieneś być złoty.

Jeśli to się nie powiedzie (nie jestem pewien co do gwarancji), można zrobić podejście brute-force siedzi w pętli, robi waitpid() z opcją NOHANG na każdym z dzieckiem PID, a następnie opóźnia na chwilę przed wykonaniem to znowu.

+0

Proszę zobaczyć kod, zrobiłem dokładnie to samo, co mówisz. – avd

+0

@aditya: Uh, nie, moja sugestia oznacza robienie jak jborque sugeruje, nie powiedziałem nic o używaniu obsługi sygnału. – unwind

Powiązane problemy