Search code examples
c++signalsstdbind

How to use std::bind function as a signal handler in C++?


I am using the following code to add signal handling to my C++ classes:

namespace {
    std::atomic<bool> signal_flag(false);   
}
void terminate_or_interrupt_handler(int signal) {
    switch (signal) {
        case SIGTERM:
            WARN("SIGTERM received");
            signal_flag.store(true);
            break;
        case SIGINT:
            WARN("SIGINT received");
            signal_flag.store(true);
            break;
        default:
            throw (std::runtime_error("Unhandled signal received"));
    }
}
signal(SIGTERM, &terminate_or_interrupt_handler);

This code works, but it requires the signal handler function to be define in the same scope as the signal flag variable. I decided to modify the code and pass the signal_flag by reference to the function and use std::bind to "specialize" the handler to my class.

 void terminate_or_interrupt_handler(std::atomic<bool>& signal_flag, int signal) {
    switch (signal) {
        case SIGTERM:
            WARN("SIGTERM received");
            signal_flag.store(true);
            break;
        case SIGINT:
            WARN("SIGINT received");
            signal_flag.store(true);
            break;
        default:
            throw (std::runtime_error("Unhandled signal received"));
    }
}
auto my_handler = std::bind(terminate_or_interrupt_handler, std::ref(my_class_signal_flag), std::placeholders::_1);
signal(SIGTERM, &my_handler);

However, I get this compile error:

error: cannot convert ‘std::_Bind<void (*(std::reference_wrapper<std::atomic<bool> >, std::_Placeholder<1>))(std::atomic<bool>&, int)>*’ to ‘__sighandler_t’ {aka ‘void (*)(int)’}

Is there a way to use a bound function in conjunction with the signal function in C++?


Solution

  • The result of std::bind is an unspecified function object whose type cannot be converted into void (*)(int). Try encapsulating it:

    void handler_foo(int signal)
    {
        return terminate_or_interrupt_handler(signal_flag, signal);
    }
    

    Or, if C++11 is available, a lambda might be better:

    signal(SIGTERM, [](int signal) { return terminate_or_interrupt_handler(signal_flag, signal); });
    

    Note that since signal_flag is a global variable (namespace-scope variable), no capture is required. A non-capturing lambda can be implicitly converted into the corresponding function pointer type.