2010-03-08 9 views
1

Est-il possible de différencier les processus enfants créés par différentes fonctions fork() dans un programme.fork() dans une fourche()

global variable i; 

SIGCHLD handler function() 
{ 
    i--; 
} 

handle() 
{ 
    fork() --> FORK2 
} 

main() 
{ 
    while(1) 
    { 
    if(i<5) 
    { 
     i++; 
     if((fpid=fork())==0) --> FORK1 
      handle() 
     else (fpid>0) 
      ..... 
    } 
    } 
} 

Est-il possible de différencier les processus enfants créés par FORK1 et FORK2? parce que j'essaye de décrémenter la valeur de la variable globale 'i' dans la fonction de gestionnaire SIGCHLD et il devrait être décrémenté seulement pour les processus créés par FORK1.

J'ai essayé d'utiliser un tableau et enregistrez l'identificateur de processus de l'enfant processus créés par FORK1 et cela est fait par le processus parent. Je décrémenter la valeur de « i » que si l'identifiant du processus enfant mort est dans le tableau ...

Mais je faisais face à un problème avec le scénario suivant

child1, Parent1, child1 tué, child2, child2 tués, parent2

Encas de child1 puisqu'il est tué après Parent1 le tableau est mis à jour correctement.

Mais dans le cas de child2 qui est tué avant que sa valeur pid ne soit mise à jour par parent2 dans le tableau? À l'intérieur de la fonction de gestionnaire de signal SIGCHLD puisque la valeur PID enfant2 ne figure pas dans le tableau, la valeur «i» ne sera pas décrémentée en conséquence.

Alors, y a-t-il une meilleure solution pour ce problème?

+0

duplication possible: http://stackoverflow.com/questions/340283/avoiding-a-fork-sigchld-race-condition – jschmier

+0

Hmmm ... en fait je ne l'avais pas trouvé plus tôt .. – codingfreak

+0

Comment définissez-vous le gestionnaire de signal ? Avec 'signal',' bsd_signal', ou 'sigaction'? – Random832

Répondre

2

Depuis que vous enregistrez déjà une liste de PIDs pour lequel vous souhaitez diminuer la valeur de i dans le gestionnaire SIGCHLD, la partie qui peut être vous trébucher reçoit un SIGCHLD supplémentaire en mettant à jour la liste.

Vous pouvez masquer/bloquer d'autres signaux SIGCHLD pendant l'exécution du gestionnaire de signaux à l'aide de sigprocmask(). Cela devrait vous donner suffisamment de temps pour mettre à jour votre tableau/liste d'ID de processus sans vous soucier de recevoir un autre SIGCHLD. Le masque bloqué doit être ramené à sa valeur d'origine lorsque la routine de gestion du signal est terminée.

Essayez d'ajouter quelque chose de semblable à ce qui suit à votre gestionnaire SIGCHLD:

sigset_t mask; 
sigset_t orig_mask; 

sigemptyset (&mask); 
sigaddset (&mask, SIGCHLD); 

/* temporarily mask/block SIGCHLD signals and save original mask */ 
if (sigprocmask(SIG_BLOCK, &mask, &orig_mask) < 0) { 
    perror ("sigprocmask - %s", strerror(errno)); 
} 

/* process SIGCHLD via waitpid() and update PID list as necessary */ 
... 

/* restore original mask */ 
if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0) { 
    perror ("sigprocmask - %s", strerror(errno)); 
} 

Mise à jour

Après avoir réexaminé votre question, je vois que vous avez une conditon course dans laquelle un processus enfant se termine avant que le processus parent puisse ajouter son PID à la liste.

Une solution possible est toujours d'utiliser sigprocmask() pour bloquer le signal SIGCHLD pendant la section critique. Dans ce cas, vous devrez bloquer le signal SIGCHLD avant votre appel au fork() et le débloquer dans le code parent après que le PID a été ajouté à la liste. Si l'enfant meurt, le gestionnaire de signal sera appelé après avoir débloqué le signal, ce qui devrait garantir que le PID est dans la liste.

+0

En fait, je ne suis pas confronté à traitement de la liste de tableaux dans la fonction de gestionnaire de signaux SIGCHLD ... Initialement, la mise à jour du tableau avec les identifiants de processus enfants est effectuée par le processus parent. Donc, dans un scénario où l'exécution est l'ordre est quelque chose comme .... enfant1, parent1, enfant2, enfant3, parent2, parent3 ... Si enfant2 est tué avant que le code parent2 est exécuté, l'ARRAY n'est pas mis à jour avec child2 PID comme résultat Le gestionnaire de signal SIGCHLD ne décrémentera pas la valeur i car le pid n'est pas présent dans le tableau – codingfreak

+0

Maintenant que j'ai une meilleure compréhension de votre problème, j'ai mis à jour ma réponse en conséquence. – jschmier

+0

Vous voulez dire que je devrais bloquer le signal SIGCHLD avant le fork() et le débloquer une fois que je suis en processus parent. – codingfreak

0

utilisation:

getppid() function . 
+0

Vous voulez dire que je devrais utiliser getppid() dans la fonction de gestionnaire de signal SIGCHILD ... ?? Dans ce cas, il n'est pas très utile ... ?? – codingfreak

0

Si je comprends bien, vous pourriez être intéressé par waitpid() appel système. Il vous permet d'attendre un enfant spécifique (donné un pid). Donc, si vous gardez une trace du pid créé par fork1 et fork2, vous devriez pouvoir décrémenter votre variable i seulement si un enfant de fork1 est mort.

+0

Afin de maintenir une liste pour tous les processus enfants créés par fork1 J'utilise un tableau dans le processus parent pour mettre à jour le tableau avec l'ID du processus fils et dans la fonction SIGCHLD J'essaye de décrémenter la valeur de i seulement si son PID est dans le tableau .. Mais il y a un problème .. si le processus de l'enfant meurt si vite que même le code dans le processus parent ne s'exécute pas alors le tableau n'est pas mis à jour avec des valeurs appropriées .. – codingfreak