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;
}
source to share
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 ableasync_wait
on it after the first signal is received. Also, in principle, I made itfirst
atomic (although this is not necessary until you runio_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....
source to share