2009-10-02 4 views
12

Dans mon programme, je suis en train de forcer (en parallèle) les processus fils dans une boucle while finie et de faire exec sur chacun d'eux. Je veux que le processus parent reprenne l'exécution (le point après cette boucle while) seulement après que tous les enfants se soient terminés. Comment devrais-je faire ça?Attente de tous les processus enfants avant que le parent ne reprenne l'exécution UNIX

J'ai essayé plusieurs approches. Dans une approche, j'ai fait une pause parent après boucle while et envoyé une condition du gestionnaire SIGCHLD seulement quand waitpid retournait l'erreur ECHILD (aucun enfant restant) mais le problème auquel je suis confronté dans cette approche est avant même que parent ait fini de forcer tous les processus, retStat devient -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 

Répondre

21

Au lieu d'appeler waitpid dans le gestionnaire de signaux, pourquoi ne pas créer une boucle après avoir bifurqué tous les processus comme suit:

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

Le programme devrait se bloquer dans la boucle jusqu'à ce qu'il n'y a pas plus d'enfants. Ensuite, il va tomber et le programme va continuer. Comme un bonus supplémentaire, la boucle va bloquer waitpid pendant que les enfants courent, donc vous n'avez pas besoin d'une boucle occupée pendant que vous attendez. Vous pouvez également utiliser wait(NULL) qui devrait être équivalent à waitpid(-1, NULL, 0). S'il n'y a rien d'autre à faire dans SIGCHLD, vous pouvez le définir sur SIG_IGN.

+0

Je dois donner l'option WNOHANG parce que s'il y a beaucoup d'enfants qui délivrent le signal SIGCHLD presque en même temps, et que les signaux ne sont pas mis en file d'attente sous UNIX, si j'utilise 0, je ne pourrai attraper qu'un seul signal être laissé. – avd

+0

Juste pour ajouter un peu, le -1 vérifiera tout enfant pid (pourrait utiliser WAIT_ANY pour plus de clarté aussi). – amischiefr

+0

@aditya: Les processus zombies n'attendent que vous pour appeler wait() (ou wait_pid()). Dès que vous le faites, ils disparaissent, que vous ayez ou non attrapé le signal. Ainsi, la boucle wait() après la boucle fork() épongera tous les zombies. –

0

Je pense que vous devriez utiliser l'appel waitpid(). Il vous permet d'attendre "n'importe quel processus enfant", donc si vous faites cela le nombre approprié de fois, vous devriez être en or.

Si cela échoue (pas sûr des garanties), vous pourriez faire l'approche force brute assis dans une boucle, en faisant un waitpid() avec l'option NOHANG sur chacun de votre enfant PIDs, puis retarder pendant un certain temps avant de le faire encore.

+0

S'il vous plaît voir le code, j'ai fait exactement la même chose que vous dites. – avd

+0

@aditya: Euh, non, ma suggestion signifie faire comme jborque le suggère, je n'ai rien dit à propos de l'utilisation d'un gestionnaire de signal. – unwind

Questions connexes