2009-03-10 12 views
3

Dans mon programme, je fork() plusieurs fois en fonction de l'entrée de l'utilisateur.Ignorer SIGCHLD dans certains cas, mais pas dans d'autres

Dans certains cas, je veux gérer SIGCHLD et dire quelque chose comme "Process # Finished". Dans d'autres cas cependant, je veux ignorer ce signal.

Comment est-ce que je peux faire ceci?

Répondre

4

La gestion des signaux est configurée globalement pour le processus. Si vous voulez attraper un signal asynchrone comme SIGCHLD quand certains enfants se terminent mais pas d'autres, vous ne pouvez pas décider de l'ignorer pour certains à l'avance.

Vous devrez gérer le signal à chaque fois dans le parent, puis décider si vous voulez l'ignorer dans votre gestionnaire. Au minimum, votre gestionnaire doit faire wait() sur l'enfant (si_pid dans la structure siginfo_t) pour récupérer son code retour. À ce stade, vous pouvez vérifier l'ID du processus et décider quoi faire d'autre. Vous n'avez rien à imprimer si vous ne le souhaitez pas.

0

Si vous ignorez SIGCHLD alors la table de processus se remplira de zombies.

+0

Dans certaines versions d'unix, ignorer SIGCHLD récupère automatiquement les processus enfants (apparemment). http://www.faqs.org/faqs/unix-faq/faq/part3/section-13.html –

2

Vous pouvez utiliser la fonction waitpid en mode bloquant ou non bloquant pour attendre le signal d'un enfant donné, puis effectuer un traitement. En fait, vous avez pour utiliser wait de quelque sorte, comme il est indiqué dans la réponse de Graham ...

3

Vous voulez attraper le signal SIGCHLD, puis appeler une fonction. Vous voulez utiliser signal() pour ce faire (man signal). Dans l'exemple ci-dessous child_died() est appelé après que le signal SIGCHLD soit intercepté (le processus enfant est mort à ce stade). S'il y a des informations dont vous avez besoin de passer de l'enfant au parent que child_died() a besoin pour un conditionnel, vous devrez utiliser un tuyau (man pipe). Voici un exemple de signal et conduite:

#include <signal.h> 
#include <strings.h> 
#include <stdio.h> 

#define MAX_SIZE 256 

void child_died(int); 

int fd[2]; 

int main() 
{ 
    int pid; 
    extern int fd[]; 
    char *str; 

    pipe(fd); 
    signal(SIGCHLD, child_died); 

    if ((pid = fork()) < 0) { 
     // error 
     printf("Error\n"); 
    } else if (pid == 0) { 
     // child 
     printf("In child process\n"); 
     close(fd[0]); 
     str = strdup("Message from child process.\n"); 
     write(fd[1], str, strlen(str) + 1); 
    } else { 
     // parent 
     wait(); 
     printf("Now in parent\n"); 
    } 

    return 0; 
} 

void child_died(int s) 
{ 
    char *str; 
    close(fd[1]); 
    read(fd[0], str, MAX_SIZE); 
    printf("%s", str); 
} 

enregistrés en tant que sigchld.c et compilé avec: gcc -Wall sigchld.c -o sigchld

Si vous voulez passer un entier (comme le pid de l'enfant) ou un autre type de données de la le processus fils vers le processus parent, vous devrez soit le convertir en une chaîne et inversement, soit trouver un autre moyen de le faire.

Si vous voulez ignorer SIGCHLD alors dans mon exemple vous mettriez cette logique dans child_died(). Utilisez simplement un simple if. Je ne sais pas comment vous décidez quand ignorer le signal et quand imprimer ce que vous voulez, c'est pourquoi j'ai inclus les trucs de pipe dans mon code ci-dessus. Je pensais que vous utiliseriez des informations du processus fils et puisque child_died() est appelée sur le processus parent, vous aurez besoin d'un moyen de transférer des données de l'enfant au processus parent.

J'espère que cela aide. Il peut y avoir des façons meilleures ou plus faciles d'accomplir cela que je ne connais pas. S'il y a alors s'il vous plaît commenter.