0

I am trying to implement system-signal handling into my code, which looks basically like this

struct Foo{
    bool should_stop_;
    std::thread* _internal_thread_;

    Foo(): should_stop_(false) {};
    // this is what the thread does at heard
    void operator()() {
        while(!should_stop_) {
            std::cout << "sleeping" <<endl;
            sleep(1);
        }
    };
    //start the execution in an thread; i.e. not blocking
    void run() {
        _internal_thread_ = new std::thread(std::ref(*this));
    };

    //end the thread execution, and join the thread
    void stop() {
        should_stop_ = true;
        _internal_thread_->join();
    }
};

int main () {
    auto foo_ptr = new Foo();

    foo_ptr->run();  // non blocking
    try{
       sleep(5);  // while(True) {do_other_things();}
    } catch(...) {
        std::cout << "unexpected.\n";
    }
    foo_ptr->stop();
};

this works quite well for me [while the program could be in principle running indefinitely, I cut I short with five cycles, to demonstrate the call to stop()]. This does, however, not handle system-signals like SIGINT, SIGTERM etc. Having read the cpp-reference on signal() I wanted to wrap my Foo object into a functor and let it Handle the signal, aka interrupt the execution of foo by calling to stop as soon as the signal is received. I tried this:


struct myHandler {
    Foo* foo_ptr_;
    myHandler(Foo* foo_ptr) : foo_ptr_(foo_ptr) {};

    void operator()(int signum) {
        call(signum);
    };

    void call(int signum) {
        std::cout << "Interrupt signal (" << signum << ") received.\n";
        foo_ptr_->stop();
        exit(signum);
    };
};



int main() {
    auto foo_ptr = new Foo();
    auto my_sighandler = myHandler(foo_ptr);
    signal(SIGINT, (void (*)(int))&my_sighandler); // -> should go through MyHandler::operator()
    signal(SIGTERM, (void (*)(int))&my_sighandler::call); // -> should go through MyHandler::call

    foo_ptr->run();
};

This, does not work for either of the two registered signals (SIGINT or SIGTERM). I can not find a viable solution to resolve this. On my quick search I was able to find some solutions which go through the length of registering global volatile variables for which their classes [what is here Foo] listen to. However this would seriously break my class design as well as violate the program structure, which should be bottom-to-top.

Can anybody provide some hints here?

mzoll
  • 475
  • 3
  • 11
  • Using casts in that way is something you should do when you know what you are doing. You can't just cast one thing to another and expect it to work. You need actual function pointers that match the signature. – super Mar 18 '21 at 16:38
  • From [cppreference.com](https://en.cppreference.com/w/cpp/utility/program/signal): _Signal handlers are **expected to have C linkage** and, in general, only use the features from the common subset of C and C++. **It is implementation-defined if a function with C++ linkage can be used as a signal handler**._ – Woodford Mar 18 '21 at 16:55
  • @woodford I have seen and read this paragraph before, but do not know, how i should interpret it in this context: Is it that me using functors, which is a class, is not strict C (even if its is **only** a struct) and thus I violate the forementioned restriction already? If my way is not the way to go about this, how could I realize what I intended [catching signals and taking action by halting/interrupting my threads **nicely** from top-to-bottom]. – mzoll Mar 19 '21 at 12:28
  • @mzoll Look up "C linkage" if you're not sure what it means. Not saying that's the problem but it's something to be aware of. Maybe the answers here will be of more help: https://stackoverflow.com/questions/22005719/which-thread-handles-the-signal – Woodford Mar 19 '21 at 16:24
  • While I have not found a proper solution to this precise problem, I found at least a workable solution using signal-pipes from `boost::signals2`, where I convert the system-signal into a signal pushed through a globally defined pipe, and any subprocesses/threads can listen on that pipe for eventual signals (by their posix-code, an integer) and react to them accordingly – mzoll Mar 30 '21 at 11:54

0 Answers0