Signals have the well known drawback that signals arrive free of context. E.g., assume a program runs a flow control loop like this:
void Class::run() { while (d_continue) handleTasks(); cleanup(); }then if the program needs to recognize a termination signal then the typical signal handler looks like this:
void signalHandler(int signal) { // perform required actions }Since the signalHandler is called asynchronically, there is no context available, and the usual way of communicating between objects and signal handlers is via static variables, like this:
// declared as static bool s_continue; bool Class::s_continue = true; void Class::run() { while (s_continue) handleTasks(); cleanup(); } // declared as static void signalHander(int signal); void Class::signalHandler(int signal) { s_continue = false; }The class Signal allows the signal handler to operate in the context of a class. The advantage of this is that static data members are no longer required and that the signal may be used to control data members of individual objects.
The signal is now handled by an object, whose class must define a member
virtual void signalHandler(size_t signum) override;and this function is responsible for handling the received signal. Since it is a member function it may affect its object's local variables and it may call its object's member functions. Static data members are not required anymore (see below for an example).
Note that, as the signal may arrive at unpredicable times data members that can be modified by signalHandler should be declared using the volatile modifier. Moreover, data that can be modified by the signalHandler member and by other class members should be protected by mutexes (cf. the C++-11 class std::mutex or pthread_mutex_lock(3posix)).
virtual void signalHandler(size_t signum) override;handling the received signal.
If the signum value that is passed to Signal's members is not a defined signal value, then an FBB::Exception exception is thrown.
#include <sys/types.h> #include <unistd.h> #include <iostream> #include "../signal" class SignalDemo: public FBB::SignalHandler { volatile size_t d_signal; volatile bool d_continue; pid_t d_pid; public: SignalDemo(); void run(); private: virtual void signalHandler(size_t signum) override; }; using namespace std; using namespace FBB; SignalDemo::SignalDemo() : d_signal(0), d_continue(true), d_pid(getpid()) {} void SignalDemo::run() { while (d_continue) { cout << "Send a SIGHUP or SIGTERM... to process " << d_pid << endl; sleep(1); } cout << "Ending `run' after receiving signal " << d_signal << endl; } void SignalDemo::signalHandler(size_t signal) { if (signal == SIGHUP) cout << "Process " << d_pid << " received SIGHUP" << endl; else if (signal == SIGTERM) { cout << "Process " << d_pid << " received SIGTERM" << endl; d_signal = SIGTERM; d_continue = false; } } int main() { SignalDemo signalDemo; Signal::instance().add(SIGHUP, signalDemo); Signal::instance().add(SIGTERM, signalDemo); signalDemo.run(); }