Is it possible to use signal inside a C++ class?
The second parameter of signal should be a pointer to a function accepting an int and returning void. What you're passing to signal is a pointer to a member function accepting an int and returning void (its type being void (myClass::*)(int)
). I can see three possibilities to overcome this issue:
1 - Your method myHandler
can be static: this is great, make it static
class myClass
{
public:
void myFunction ()
{
signal(SIGIO, myClass::myHandler);
}
static void myHandler (int signum)
{
// handling code
}
};
2 - Your method shouldn't be static: if you're planning to use signal with only one instance, you can create a private static object, and write a static method that simply call the method on this object. Something along the lines of
class myClass
{
public:
void myFunction ()
{
signal(SIGIO, myClass::static_myHandler);
}
void myHandler (int signum)
{
// handling code
}
static void static_myHandler(int signum)
{
instance.myHandler(signum);
}
private:
static myClass instance;
};
3 - However, if you're planning on using the signal with multiple instances, things will get more complicated. Perhaps a solution would be to store each instance you want to manipulate in a static vector, and invoking the method on each of these :
class myClass
{
public:
void myFunction () // registers a handler
{
instances.push_back(this);
}
void myHandler (int signum)
{
// handling code
}
static void callHandlers (int signum) // calls the handlers
{
std::for_each(instances.begin(),
instances.end(),
std::bind2nd(std::mem_fun(&myClass::myHandler), signum));
}
private:
static std::vector<myClass *> instances;
};
and somewhere, do a single call to
signal(SIGIO, myClass::callHandlers);
But I think that if you end up using the last solution, you should probably think about changing your handling design :-)!
Catching signals: Use a member function as signal handler
- 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
How to use std::bind function as a signal handler in C++?
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.
Interruption handling with non-static member function
No, you can not do this.
The reason is that all member functions have an "implied/hidden" this
pointer argument. If we "flattened" out your handler definition to produce the C equivalent, it would look like:
void SocketServer::signalHandler(SocketServer *this,int sig);
The signal
function [in C] knows nothing of this [pun intended]. If it compiled, the handler would be called with sig
going into the this
argument and not the sig
argument.
So, you really must do:
SocketServer my_global_server;
void
my_handler(int sig)
{
my_global_server.signalHandler(sig);
}
int
main(void)
{
signal(SIGABRT,my_handler);
return 0;
}
Actually, the above is quite dangerous because my_global_server
may be in an indeterminate state when the signal handler is called, causing UB. Also, when in a signal handler, there are a limited number of things you are permitted to do. For example, no heap manipulations are permitted.
Here is a better way to implement this:
volatile int signal_flag;
SocketServer my_global_server;
void
my_handler(int sig)
{
signal_flag = sig;
}
int
main(void)
{
signal(SIGABRT,my_handler);
while (! signal_flag) {
...
}
my_global_server.signalHandler(signal_flag);
return 0;
}
How to register a signal handler as a class method?
Being a C function, signal
can only take a plain function pointer, not arbitrary callable types. You'll need a non-member wrapper function, and a global variable to store this
, in order to call a member function from a signal handler.
static A * signal_object;
extern "C" void signal_handler(int signum) {signal_object->f(signum);}
// later...
signal_object = this;
signal(SIGSEGV, signal_handler);
Related Topics
Why Uninitialized Global Variable Is Weak Symbol
Std::Lower_Bound Slower for Std::Vector Than Std::Map::Find
How to Restart Linux from Inside a C++ Program
How to Calculate a Sha-512 Hash in C++ on Linux
How to Compile: Unrecognized Relocation
Given a Start and End Point, and a Distance, Calculate a Point Along a Line
C++ Destruction of Temporary Object in an Expression
How to Check for Inf (And | Or) Nan in a Double Variable
C++11 Random Number Distributions Are Not Consistent Across Platforms -- What Alternatives Are There
G++ Can't Find Boost Libraries. I Say They'Re in Plain Sight
C++ 'Strcpy' Gives a Warning (C4996)
Is There Any Function Equivalent to Matlab's Imadjust in Opencv with C++
Enumerate Com Object (Idispatch) Methods Using Atl
Programmatically Counting Cache Faults
Can a C Compiler Rearrange Stack Variables