Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active January 7, 2020 13:44
Show Gist options
  • Select an option

  • Save kristopherjohnson/4a1e8630cfe9fca26a56 to your computer and use it in GitHub Desktop.

Select an option

Save kristopherjohnson/4a1e8630cfe9fca26a56 to your computer and use it in GitHub Desktop.
Handling SIGHUP, SIGUSR1, and SIGUSR2 signals in a multithreaded C++ program
CXXFLAGS=-std=c++11
sigtest: sigtest.cpp
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
static void* signalHandlerThread(void* arg)
{
// Use signal mask provided by main().
// The signals we want to catch with sigwait() must already be blocked.
auto signals = static_cast<sigset_t *>(arg);
auto count = 0;
auto terminateRequested = false;
while (!terminateRequested) {
int signalNumber = 0;
auto status = sigwait(signals, &signalNumber);
if (status == 0) {
switch (signalNumber) {
case SIGHUP:
std::cout << ++count << ": Received HUP" << std::endl;
break;
case SIGUSR1:
std::cout << ++count << ": Received USR1" << std::endl;
break;
case SIGUSR2:
std::cout << ++count << ": Received USR2" << std::endl;
break;
case SIGTERM:
std::cout << ++count << ": Received TERM" << std::endl;
terminateRequested = true;
break;
case SIGINT:
std::cout << ++count << ": Received INT" << std::endl;
terminateRequested = true;
break;
default:
std::cout << "Received signal number " << signalNumber << std::endl;
break;
}
}
else {
std::cerr << "sigwait() returned " << status;
}
}
return nullptr;
}
int main(int argc, const char* argv[])
{
// Set signal mask to block any signals we want to catch.
// Any spawned threads will inherit this signal mask.
auto signalNumbers = { SIGHUP, SIGUSR1, SIGUSR2, SIGTERM, SIGINT };
sigset_t signals;
sigemptyset(&signals);
for (auto signalNumber: signalNumbers) {
sigaddset(&signals, signalNumber);
}
pthread_sigmask(SIG_BLOCK, &signals, nullptr);
// Spawn our signal-handling thread, passing it our set of blocked signals
pthread_t thread;
pthread_create(&thread, nullptr, signalHandlerThread, &signals);
// Tell user how to send the signals to us
std::cerr << "sigtest waiting for signals; run this command:\n kill -HUP "
<< getpid()
<< "\n or -USR1|-USR2|-TERM|-INT"
<< std::endl;
// Wait for the signal-handling thread to terminate
void *threadResult = nullptr;
pthread_join(thread, &threadResult);
std::cerr << "<Program exit>" << std::endl;
return 0;
}
@kristopherjohnson
Copy link
Author

Note that this was written/tested on OS X. Every variant of UNIX has its own quirks in its signals API, so read the docs for pthread_sigmask() and sigwait() to be sure it's going to work like you expect.

@1Hyena
Copy link

1Hyena commented May 24, 2018

Why would you spawn a new thread? Why not call sigwait from main?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment