gestionnaire de signal ne fonctionne pas

zmq bibliothèques czmq et zmq dans mon code. J’ai enregistré un gestionnaire de signaux pour SIGINT en appelant signal dans main. Le code ressemble à ceci:

 #include "czmq.h" void sig_int(int signal); void* pub_handler(){ zctx_t *context = zctx_new (); void *publisher = zsocket_new (context, ZMQ_PUB); zsocket_connect (publisher, "tcp://localhost:5555"); sleep(1); char topic[20] = "REQ: speedlimit"; // while (true) { sleep( randof(10) ); zstr_sendm (publisher, topic); zstr_send (publisher, "driver analysis data"); } zctx_destroy (&context); } void* sub_handler(){ zctx_t *context = zctx_new(); void *subscriber = zsocket_new (context, ZMQ_SUB); zsocket_connect (subscriber, "tcp://localhost:5557"); srandom ((unsigned) time (NULL)); char subscription [20] = "RESP: speedlimit" ; zsocket_set_subscribe (subscriber, subscription); while (true) { char *topic = zstr_recv (subscriber); if(!topic) break; char *data = zstr_recv (subscriber); assert (streq (topic, subscription)); puts (topic); puts (data); free (topic); free (data); } zctx_destroy (&context); } int main(int argc, const char *argv[]) { pthread_t pub_id, sub_id; signal (SIGINT, sig_int); pthread_create(&pub_id, NULL, pub_handler, NULL); pthread_create(&sub_id, NULL, sub_handler, NULL); pthread_join(pub_id, NULL); pthread_join(sub_id, NULL); return 0; } void sig_int(int signal){ printf (" Interrupted\n"); exit(0); } 

compilé en tant que gcc -o app app.c -lpthread -lczmq -lzmq .

Le code ci-dessus n’entre pas dans le gestionnaire de signal lorsque ctrl+c interruption est donné.

quel est le problème avec la bibliothèque czmq ou zmq et comment le gérer?

La documentation de zctx indique que zctx configure son propre gestionnaire de signal pour SIGINT et SIGTERM , annulant probablement votre gestionnaire de signal.

Configure le traitement des signaux (SIGINT et SIGTERM) de sorte que les appels bloquants tels que zmq_recv () et zmq_poll () reviennent lorsque l’utilisateur appuie sur Ctrl-C.

Il indique également que zctx est déconseillé au profit de zsock , qui ne semble pas configurer de gestionnaire de signal conformément à sa documentation. Ma première suggestion consiste donc à utiliser la nouvelle API de socket zsock .

Cependant, il semble que dans les deux cas, vous pouvez également appeler zsys_handler_set(NULL); (documenté ici ) pour désactiver explicitement la gestion par défaut de SIGINT / SIGTERM dans CZMQ.

PS: printf n’est pas protégé contre le signal asynchrone, ce qui signifie qu’il ne doit pas être utilisé dans un gestionnaire de signaux. Voir ici la liste des fonctions sécurisées pour les signaux asynchrones dans POSIX.

Vous avez la solution après avoir posté la question dans la zmq mailing list !!

Pieter Hintjens dit: :: CZMQ met en place sa propre gestion du signal pour intercepter SIGINT et SIGTERM. Vous pouvez le désactiver en appelant

 zsys_handler_set (NULL); 

L’ajout de la ligne ci-dessus dans mon code a désactivé la configuration du gestionnaire de signaux par czmq et je peux maintenant utiliser mon propre gestionnaire de signaux.

Merci à Pieter Hintjens.

quel est le problème …

De l’ man signal :

Les effets de signal () dans un processus multithread ne sont pas spécifiés.

Utilisez sigaction() place.

Je pense que votre problème n’a rien à voir avec CZMQ en tant que tel, et est causé par votre threading. Plus précisément, le thread principal capture le signal, contrairement au thread enfant. Ceci est un piège commun.

Il y a plusieurs solutions. Ce que je ferais peut-être, c’est dormir / attendre dans le thread principal (vous pouvez par exemple utiliser zmq_poll) puis, lorsque vous recevez le signal, dites aux threads enfants de se terminer.

Quelques commentaires … si vous allez utiliser CZMQ, alors pourquoi ne pas utiliser ses fonctions de threading, qui encapsulent les pthreads dans une interface plus agréable. Vous avez l’ancienne classe zthread et la nouvelle classe zactor.

Je pense que votre programme principal devrait être en vie. Essaye ça-

 int main(int argc, const char *argv[]) { pthread_t pub_id, sub_id; signal (SIGINT, sig_int); pthread_create(&pub_id, NULL, pub_handler, NULL); pthread_create(&sub_id, NULL, sub_handler, NULL); pthread_join(pub_id, NULL); pthread_join(sub_id, NULL); while(1); // Fix } 

Vous avez modifié la table des signal aide de signal fonction signal .

 signal (SIGINT, sig_int); 

Ainsi, chaque fois que vous donnerez un signal SIGINT (ctrl + c), la fonction sig_int sera appelée. C’est votre gestionnaire de signal. Mais dans cette fonction, vous ne tuez aucun processus.

Ainsi, chaque fois que vous appuyez sur ctrl + c , votre programme appelle simplement la fonction sig_int . Cette fonction imprimera Interrupted pour chaque signal SIGINT .

Si vous souhaitez que votre programme se termine lorsque vous appuyez sur ctrl+c , ne modifiez pas la table de signaux comme ci-dessous.

 signal (SIGINT, sig_int); 

Au lieu de

 signal (SIGINT, SIG_DFL); 

Il mettra fin à votre programme lorsque vous ctrl+c sur ctrl+c .

Sinon, vous pouvez essayer aussi

 void sig_int(int signal){ signal (SIGINT, SIG_DFL); // here i am again changing the signal table to default. printf (" Interrupted\n"); exit(0); } 

Dans ce cas, lorsque vous ctrl+c sur ctrl+c première fois, la fonction sig_int sera appelée, mais lorsque vous sig_int une seconde fois, votre programme sera terminé. parce que j’ai modifié la table des signaux dans votre fonction sig_int .