Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Waking up thread from signal handler

I understand that about the only thing, a signal handler in ISO/C++11 is allowed to do is to read from or write to a lock free atomic variable or a volatile sig_atomic_t (I believe, POSIX is a little bit more permissive and allows to call a bunch of system functions).

I was wondering, if there is any way, to wake up a thread that is waiting on a condition variable. I.e. something like:

#include <mutex>
#include <atomic>
#include <condition_variable>


std::mutex mux;
std::condition_variable cv;

std::atomic_bool doWait{ true };

void signalHandler(int){
    doWait = false;
    cv.notify_one();
}

int main() {
    //register signal handler
    //Do some stuff

    {//wait until signal arrived
        std::unique_lock<std::mutex> ul(mux);
        cv.wait(ul, []{return !doWait; });
    }

    //Do some more stuff
}

Which has at least two problems:

  1. I believe, I'm not allowed to call notify_one() in a signal handler (corrct me if I'm wrong)
  2. The signal could arrive just between the check for doWait and when the thread goes to sleep, so it would never wake up (obviously, I can't lock the mutex in the signalHander to avoid that).

So far, the only solution I can see is to implement busy waiting on the doWait variable (probably sleep for a couple of milliseconds in each iteration), which strikes me as quite inefficient.

Note that even though, my program above has only one thread, I labeled my question with multithreading, because it is about thread control primitives. If there is no solution in standard c++ I'd be willing to accept a solution using Linux/POSIX specific functions.

like image 567
MikeMB Avatar asked Jun 29 '15 14:06

MikeMB


People also ask

Is pthread_ cond_ signal thread safe?

It is not safe to use the pthread_cond_signal() function in a signal handler that is invoked asynchronously.

How does pthread_ cond_ signal work?

The pthread_cond_signal() call unblocks at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond). The pthread_cond_broadcast() call unblocks all threads currently blocked on the specified condition variable cond.

Are signal handlers per thread?

signal is a per process call, not a per thread one, if you call it it sets the handler for all threads in the process. Signals and threads is a complex topic.

What happens when a thread gets a signal?

The signal is delivered once to any thread that is configured to receive it. The thread, which is asynchronously handling the signal, stops whatever it is doing and jumps to the configured signal handler. The flow of the execution in the remaining threads is unaffected.


1 Answers

Assuming that your vendor's standard library uses the pthread_cond_* functions to implement C++11 condition variables (libstdc++ and libc++ do this), the pthread_cond_* functions are not async-signal-safe so cannot be invoked from a signal handler.

From http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_broadcast.html:

It is not safe to use the pthread_cond_signal() function in a signal handler that is invoked asynchronously. Even if it were safe, there would still be a race between the test of the Boolean pthread_cond_wait() that could not be efficiently eliminated.

Mutexes and condition variables are thus not suitable for releasing a waiting thread by signaling from code running in a signal handler.

If you're comfortable using semaphores, sem_post is designated async-signal-safe. Otherwise, your options for signal handling are the usual ones: the classic self-pipe, a signal handling thread blocked on sigwait/sigwaitinfo, or platform-specific facilities (Linux signalfd, etc.).

like image 88
ecatmur Avatar answered Sep 19 '22 01:09

ecatmur