简体   繁体   中英

signal handler not working

I'm using czmq and zmq libraries in my code. I've registered a signal handler for SIGINT by calling signal in main. The code looks like this:

#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);
}

compiled as gcc -o app app.c -lpthread -lczmq -lzmq .

The above code doesn't get into signal handler when ctrl+c interrupt is given.

what is the problem with czmq or zmq library and how it should be handled?

The documentation for zctx says that zctx sets up its own signal handler for SIGINT and SIGTERM , probably overriding your signal handler.

Sets up signal (SIGINT and SIGTERM) handling so that blocking calls such as zmq_recv() and zmq_poll() will return when the user presses Ctrl-C.

It also says that zctx is deprecated in favor of zsock , which doesn't appear to setup a signal handler according to its documentation. So my first suggestion is to use the new zsock socket API.

However, it seems that in both cases you can also call zsys_handler_set(NULL); (documented here ) to explicitly disable the default SIGINT/SIGTERM handling in CZMQ.

PS: printf is not async-signal-safe, meaning that it should not be used in a signal handler. See here for a list of async-signal-safe functions in POSIX.

Got the solution after posting the question in zmq mailing list !!

Pieter Hintjens say's :: CZMQ does set up its own signal handling to trap SIGINT and SIGTERM. You can disable this by calling

zsys_handler_set (NULL);

Adding the above line in my code disabled the signal handler setup by czmq and now I can use my own signal handler.

Thanks to Pieter Hintjens.

what is the problem ...

From man signal :

The effects of signal() in a multithreaded process are unspecified.

Use sigaction() instead.

I think your problem has nothing to do with CZMQ as such, and is caused by your threading. Specifically, the main thread is catching the signal, and the child thread is not. This is a common trap.

There are several solutions. What I'd perhaps do is sleep/wait in the main thread (you can eg use zmq_poll) and then when you get the signal, tell the child threads to end.

Some comments... if you are going to use CZMQ, then why not use its threading facilities, which wrap pthreads in a nicer interface. You have the older zthread class, and the newer zactor class.

I think your main program should be alive. Try this-

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
}

You have changed the signal table using signal function.

signal (SIGINT, sig_int);

So whenever you will give SIGINT signal(ctrl+c), it will call the sig_int function. That is your signal handler. But in that function you are not killing any process.

So whenever you press ctrl + c , your program just call's the sig_int function, That function will print Interrupted for every SIGINT signal.

If you need your program want's to terminate when you press ctrl+c , don't modify the signal table like below.

signal (SIGINT, sig_int);

Instead of that

signal (SIGINT, SIG_DFL);

It will terminate your program, when you press ctrl+c .

Else you can try this also-

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

In this case, when you press ctrl+c first time it will call the sig_int function, but when you press second time it will terminate your program. because i have modified the signal table inside your sig_int function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM