Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use signal inside a C++ class?

I am doing something like this:

#include <signal.h>  class myClass { public:      void myFunction ()      {         signal(SIGIO,myHandler);     }      void myHandler (int signum)     {         /**         * Handling code         */     }  } 

I am working on Ubuntu, using gcc.

But it won't compile. It is complaining with:

error: the argument with type void (MyClass::)(int) doesn't agree with void (*) (int)

Any clues? Or maybe it is just that I cannot use a signal inside classes? Are signals only allowed in C?

The error message is an approximate translation because my compiler is not in English.

like image 986
Pablo Herrero Avatar asked Dec 05 '08 08:12

Pablo Herrero


People also ask

How does signal in C work?

A signal is a software generated interrupt that is sent to a process by the OS because of when user press ctrl-c or another process tell something to this process.

Is printf signal safe?

It is not safe to call all functions, such as printf , from within a signal handler. A useful technique is to use a signal handler to set a flag and then check that flag from the main program and print a message if required.

Can a signal handler take arguments?

Absolutely. You can pass integers and pointers to signal handlers by using sigqueue() instead of the usual kill().


1 Answers

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 :-)!

like image 119
Luc Touraille Avatar answered Sep 19 '22 03:09

Luc Touraille