Search code examples
c++signal-handling

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.


Solution

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