nunojpg
nunojpg

Reputation: 505

c++ signal handler can wake a thread?

Since a C++ signal handler should only access volatile std::sig_atomic_t or std::atomic(since C++11), is it possible to have a thread sleeping and wake with it?

std::atomic_bool exit_now(false);

void signal_handler(int signal)
{
  exit_now=true;
}

int main() {

      std::signal(SIGINT, signal_handler);

      A a;
      B b;

      a.RunAsync();
      b.RunAsync();

      while(!exit_now)
          std::this_thread::sleep_for(std::chrono::seconds(1));

      a.Stop();
      b.Stop();

      return 0;
}

In this case, A and B ::RunAsync() both do their business on other threads until I call ::Stop(), so my only option is to busy-wait on the main thread (with or without a predefined sleep period).

Ideally I would want the main thread to sleep until signaled, possibly with a condition variable, but that looks illegal to do.

Upvotes: 4

Views: 1172

Answers (2)

Imanol Barba Sabariego
Imanol Barba Sabariego

Reputation: 115

What you're after is a way to wake up the thread in a manner that is async-signal-safe.

My preferred way of doing this in Linux is using POSIX semaphores. Bear in mind this might not be portable to other operating systems as POSIX semaphores are not required for an OS to be considered POSIX compliant.

  1. Before registering the signal handlers:
  // signalSemaphore is a global variable
  if (sem_init(&signalSemaphore, 0, 0)) {
    std::cerr << "Unable to initialise semaphore: " << strerror(errno);
    return 1;
  }
  1. From the thread you want to wake up:
while(sem_wait(signalSemaphore)) {
  if(errno != EINTR) {
    // call can be interrupted, so if the error is EINTR we ignore it
    std::cerr << "Error waiting for signal semaphore: " << strerror(errno);
  }
}
  1. From the signal handler, bump the semphore to 1. This will unblock the sem_wait() call:
void signalHandler(int signal) {
  sem_post(&signalSemaphore);
}

Alternatively, using pipes is also an option since the read() and write() syscalls are also async-signal-safe, and pipes is a more portable mechanism. See an example on how to do it here: How can I wake a thread in macOS in a way that is async-signal-safe?

Upvotes: 0

Seg Fault
Seg Fault

Reputation: 1351

I would suggest (blocking the signals and) using sigwait(2) to synchronously wait for the signals in the main thread, then you completely circumvent the issue of having to communicate from a signal handler to a thread.

Upvotes: 2

Related Questions