I have an object which does some work in an endless loop. The main()
instantiates the object and calls the run()
method. Since I don't want to use threads, I need a solution to make my object stop running. Below you see what I've come up with.
struct Foo
{
void run()
{
running = 1;
while (running)
do_something_useful();
std::cout << "Execution stopped." << std::endl;
}
bool running;
void catch_signal(int signal)
{
std::cout << "Caught signal " << signal << std::endl;
if( signal == SIGTERM )
running = false;
}
};
As you see, I need to send a signal asynchronously. Therefore, I use a signal handler and sigaction
. Below the main
I can imagine to use.
int main(int argc, char** argv)
{
Foo foo;
struct sigaction sigIntHandler;
boost::function< void (int) > f;
f = std::bind1st(
std::mem_fun(&Foo::catch_signal), &foo);
f(5); // this call works
sigIntHandler.sa_handler = f; // compiler complains, "cannot assign ..."
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGTERM, &sigIntHandler, NULL);
s.run();
}
What I would expect now: The program runs until I send SIGTERM
which is caught and will cause my object to stop iteration and return to main.
I have two questions now:
(a) In the code you see a line marked with "Compiler complains", the message is like
boost::function<void(int)> cannot be converted to __sighandler_t {aka void (*)(int)}
What do I need to change to make this work? I think f
is like void f(int)
, like the functions the signal handler gets in some examples.
(b) For those of you who wonder "what is that guy doing?": Do you have any advice how to solve this kind of thing better?
The C library function void (*signal(int sig, void (*func)(int)))(int) sets a function to handle signal i.e. a signal handler with signal number sig.
A signal handler is a function which is called by the target environment when the corresponding signal occurs. The target environment suspends execution of the program until the signal handler returns or calls longjmp() . Signal handlers can be set with signal() or sigaction() .
sigaction() can be called with a NULL second argument to query the current signal handler. It can also be used to check whether a given signal is valid for the current machine by calling it with NULL second and third arguments. It is not possible to block SIGKILL or SIGSTOP (by specifying them in sa_mask).
- What do I need to change to make this work? I think f is like void f(int), like the functions the signal handler gets in some examples.
The compiler complains about the type, therefore you need to pass a function pointer, not an object of type boost::function<void(int)>
. Creating a global variable of this type, and adding a function which calls this object would work :
boost::function<void(int)> myCb;
void CallCb( int value )
{
myCb(value);
}
int main(int argc, char** argv)
{
Foo foo;
struct sigaction sigIntHandler;
myCb = std::bind1st(
std::mem_fun(&Foo::catch_signal), &foo);
f(5); // this call works
sigIntHandler.sa_handler = CallCb;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGTERM, &sigIntHandler, NULL);
s.run();
}
- Do you have any advice how to solve this kind of thing better?
Not really. The idea is ok. I would just just c++11 lambda instead
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With