简体   繁体   中英

C: Signal handling and semaphores

I'm trying to better understand semaphores and all that jazz and for that I'm programming a server and clients that communicate using shared memory and semaphores. It works pretty well and everything, but I'm not sure I understand how signal handling properly works in this case. This is some sample code from my server. I realize it may be a bit redundant to check both, but I kinda would like to understand the weird behaviour I'm experiencing:

sig_atomic_t running = 1;

while(running == 1) {
    if (sem_wait(server) == -1) {
        //exit and print error A
    }
    if(running == 0) {
        //exit and print error B
    }
    /* do server stuff */

    if (sem_post(client) == -1) {
        //exit and print error
    }
}

server is the server semaphore name, client is the client semaphore name (which doesn't really matter in this case). running (which is actually global) is the variable I use in my signal handler:

static void init_signalhandler() {
    struct sigaction sa;
    sa.sa_handler = terminate;

    if(sigemptyset(&(sa.sa_mask)) == -1) {
        bail_out(EXIT_FAILURE, "sigemptyset error");
    }

    if(sigaction(SIGINT, &sa, NULL) == -1) {
        bail_out(EXIT_FAILURE, "sigaction1 error");
    } 

    if(sigaction(SIGTERM, &sa, NULL) == -1) {
        bail_out(EXIT_FAILURE, "sigaction2 error");
    }
}

static void terminate(int e) {
    running = 0;
    sem_post(server);
}

Where bail_out is a custom error printing/exiting function.

Basically no matter what I do, whenever I start up the server, it gets to the sem_wait(server) part. If I try to kill it by sending SIGINT, sometimes, it prints error A, and other times, it prints error B. This appears to be completely random. It kinda forces me to use the running variable though, since sometimes, the semaphore gets passed, while at other times, it does not.

As you don't handle the EINTR from sem_wait(3) the behaviour is exactly as it should be.

Eg you wait at sem_wait(server) . You get the SIGINT and handle it correctly. Your sem_wait function will return -1 and you will bail out. What you should do instead:

    if (sem_wait(s_server) == -1) {
        if(errno == EINTR) continue;
        bail_out(EXIT_FAILURE, "sem_wait(3) failed");
    }

This will catch errors due to signals in the sem_wait routine and you can terminate your server gracefully as you skip to the start of the loop, see that running is set to 0 and skip the loop.

See the manual page sem_wait(3), "Return Values" for more details on which errors can be handled.

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