2016-01-26 1 views
3

J'ai un problème avec ce petit morceau de code. J'ai un "serveur" et un "client". Le serveur attend SIGUSR1 du client. Mais quand j'envoie SIGUSR1 dans une boucle, le serveur ne gère pas tous les signaux! Je fais i++ chaque fois que je reçois un signal, et je reçois 981 alors que j'envoie 1000 signaux.mon serveur ne gère pas tous les signaux quand je lui envoie beaucoup de commandes kill()

usleep() et sleep() ne aide pas.

est ici le code client:

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

int  main(int ac, char **av) 
{ 
    int i = 0; 
    int status = 0; 

    if (ac < 2) 
    return (0); 
    printf("kill %s (%d)", av[1], atoi(av[1])); 
    for (i=0;i<=1000;i++) 
    { 
     printf("%d\n", i); 
     kill(atoi(av[1]), SIGUSR1); 
    } 
    kill(atoi(av[1]), SIGUSR2); 
} 

et le code du serveur:

#include <signal.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
int i = 0; 

void sig2(int signum) 
{ 
    /* usleep(30); */ 
    printf("%d\n", i); 
    i = 0; 
} 

void my_handler(int signum) 
{ 
    i++; 
} 

int  main() 
{ 
    printf("pid: %d\n", getpid()); 
    if (signal(SIGUSR1, my_handler) == SIG_ERR) 
    { 
     printf("rt\n"); 
     exit(0); 
    } 
    signal(SIGUSR2, sig2); 
    while (1); 
} 
+2

Une note: 'printf' n'est pas" async-signal safe ", ce qui signifie que l'appeler d'un gestionnaire de signal est dangereux (IOW, ne le faites pas), mais dans ce cas très simple je suppose c'est correct, car votre boucle 'while (1);' n'appelle aucune fonction de bibliothèque standard (directement ou indirectement). – hyde

+0

effectivement le code posté essaie d'envoyer 1001 commandes 'kill'. Suggestion de remplacer: 'pour (i = 0; i <= 1000; i ++)' avec: 'pour (i = 0; i <1000; i ++)' – user3629249

+0

la fonction: 'atoi()' est relativement chère. suggérer d'ajouter une variable locale pour contenir le résultat de l'appel à 'atoi()' comme dans: 'int pid = atoi (av [1];' puis modifier la boucle pour utiliser la nouvelle variable locale plutôt que d'appeler 'atoi) ' – user3629249

Répondre

5

Il vous manque quelques signaux qui arrivent "l'un sur l'autre", trop vite pour que l'application les gère.

Le standard says:

Si un événement subséquent d'un signal en attente est généré, il est défini par l'implémentation de savoir si le signal est délivré ou accepté plus d'une fois dans des circonstances autres que celles où faire la queue est requis.

... ce qui est une manière quelque peu obscure de dire que les signaux UNIX ordinaires n'ont pas besoin d'être mis en file d'attente. Sur la plupart des implémentations, ils ne le font pas. Par exemple, si cinq signaux SIGFOO sont générés avant d'être éliminés, un seul sera retenu et l'application n'en recevra qu'un seul.

1

Le comportement de signal n'est pas cohérente entre les plates-formes, sur certains systèmes signaux sont un coup, sur les autres ça se répète. Linux, en particulier, utilise le comportement System V (sauf si la macro _BSD_SOURCE est définie) qui est one-shot. Après qu'un signal ait été traité, il se réinitialise à SIG_DFL.

Pour obtenir un comportement cohérent, vous devez utiliser sigaction à la place où le comportement peut être défini à l'aide de drapeaux.

+0

sigaction est un bon conseil, mais le problème de l'OP n'est pas la sémantique historique BSD SA_RESETHAND.C'est quelque chose que l'OP remarquerait avec deux signaux, pas avec mille. – pilcrow