Boost :: asio signal_set is only executed after the first signal is caught and ignores consecutive signals of the same type

I have a program and I would like to stop it by sending it SIGINT

to write some data to a file instead of exiting immediately. However, if the user of the program submits SIGINT

again, then the program should immediately exit and forget about writing the data to the file.

For the sake of portability, I would like to use boost::asio

for this purpose.

My original (simplified) approach (see below) doesn't work. Isn't this possible or am I missing something?

The handler seems to be called only once (prints out a message) and the program always stops when the loop has reached its maximum iteration number.

void handler(
const boost::system::error_code& error,
int signal_number) {
    if (!error) {
        static bool first = true;
        if(first) {
            std::cout << " A signal(SIGINT) occurred." << std::endl;
            // do something like writing data to a file
            first = false;
        }
        else {
            std::cout << " A signal(SIGINT) occurred, exiting...." << std::endl;
            exit(0);
        }
    }
}

int main() {
    // Construct a signal set registered for process termination.
    boost::asio::io_service io;
    boost::asio::signal_set signals(io, SIGINT);

    // Start an asynchronous wait for one of the signals to occur.
    signals.async_wait(handler);
    io.run();
    size_t i;

    for(i=0;i<std::numeric_limits<size_t>::max();++i){
        // time stepping loop, do some computations
    }

    std::cout << i << std::endl;
    return 0;
}

      

+3


source to share


1 answer


When your first event is processed, you are not posting any new work on the service object, so it exits.

This means that then (after the ioservice exits) a hard loop is started. This may not be what you expected.



  • If you want to listen to SIGINT again, you have to wait for the signal to be asserted again from the handler:

    #include <boost/asio.hpp>
    #include <boost/asio/signal_set.hpp>
    #include <boost/bind.hpp>
    #include <boost/atomic.hpp>
    #include <iostream>
    
    void handler(boost::asio::signal_set& this_, boost::system::error_code error, int signal_number) {
        if (!error) {
            static boost::atomic_bool first(true);
            if(first) {
                // do something like writing data to a file
                std::cout << " A signal(SIGINT) occurred." << std::endl;
                first = false;
    
                this_.async_wait(boost::bind(handler, boost::ref(this_), _1, _2));
            }
            else {
                std::cout << " A second signal(SIGINT) occurred, exiting...." << std::endl;
                exit(1);
            }
        }
    }
    
    int main() {
        // Construct a signal set registered for process termination.
        boost::asio::io_service io;
        boost::asio::signal_set signals(io, SIGINT);
    
        // Start an asynchronous wait for one of the signals to occur.
        signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
        io.run();
        return 2;
    }
    
          

    As you can see, I have attached a link signal_set&

    to the handler so I can be able async_wait

    on it after the first signal is received. Also, in principle, I made it first

    atomic (although this is not necessary until you run io_service

    for multiple threads).

  • Did you really want to run io_service

    in the background? In this case, do this:

    signals.async_wait(boost::bind(handler, boost::ref(signals), _1, _2));
    
    boost::thread(boost::bind(&boost::asio::io_service::run, boost::ref(io))).detach();
    
    while (true)
    {
        std::cout << "Some work on the main thread...\n";
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    }
    
          

    With a typical yield:

    Some work on the main thread...
    Some work on the main thread...
    Some work on the main thread...
    ^CSome work on the main thread...
     A signal(SIGINT) occurred.
    Some work on the main thread...
    Some work on the main thread...
    ^CSome work on the main thread...
     A second signal(SIGINT) occurred, exiting....
    
          

+5


source







All Articles