[Asio] run_one does not seem to run signal handler but run does
Hi, I am reasonably new to Boost.Asio. Below is a short test program to catch CNTR C. It nearly works as i would have expected. #include <iostream> #include <boost/version.hpp> #define BOOST_ASIO_ENABLE_HANDLER_TRACKING #include <boost/asio.hpp> namespace asio = boost::asio; #define GCC_VERSION (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__ ) struct Sig_handler { Sig_handler(int& count, asio::signal_set& signals) : count_(count), signals_(signals) {} void operator()(const boost::system::error_code& ec, int signal_number) { if (!ec) { count_++; std::cout << "signal: " << signal_number << std::endl; if (count_ < 3) signals_.async_wait( Sig_handler(count_, signals_)); } else { std::cout << "Sig_handler error" << std::endl; } } int& count_; asio::signal_set& signals_; }; int main() { std::cout << "test_asio_sig starting " << std::endl; std::cout << "GCC VERSION " << GCC_VERSION << std::endl; std::cout << "BOOST VERSION " << BOOST_VERSION << std::endl; asio::io_service io_service; asio::signal_set signals(io_service, SIGINT); int count = 0; std::cout << "count " << count << std::endl; signals.async_wait( Sig_handler(count, signals) ); size_t num_handlers = io_service.run(); // size_t num_handlers = io_service.run_one(); // <<== NOTE std::cout << "num handlers " << num_handlers << std::endl; std::cout << "count " << count << std::endl; std::cout << "test_asio_sig finishing " << std::endl; } Here is the output after pressing CNTR C 3 times [robert@localhost misc]$ ./test_asio_sig test_asio_sig starting GCC VERSION 40902 BOOST VERSION 105700 count 0 @asio|1425176527.462503|0*1|signal_set@0x7fffcd9139b8.async_wait ^C@asio|1425176530.453067|>1|ec=system:0,signal_number=2 signal: 2 @asio|1425176530.453092|1*2|signal_set@0x7fffcd9139b8.async_wait @asio|1425176530.453102|<1| ^C@asio|1425176533.749159|>2|ec=system:0,signal_number=2 signal: 2 @asio|1425176533.749187|2*3|signal_set@0x7fffcd9139b8.async_wait @asio|1425176533.749191|<2| ^C@asio|1425176548.261061|>3|ec=system:0,signal_number=2 signal: 2 @asio|1425176548.261092|<3| num handlers 6 count 3 test_asio_sig finishing @asio|1425176548.261116|0|signal_set@0x7fffcd9139b8.cancel [robert@localhost misc]$ I don't understand why io_service.run() says 6 handlers where invoked but otherwise it seems OK. Now if i replace io_service.run() with io_service.run_one() i expected the handler to be invoked once when CNTR C is pressed. Here is the output [robert@localhost misc]$ ./test_asio_sig test_asio_sig starting GCC VERSION 40902 BOOST VERSION 105700 count 0 @asio|1425176928.548934|0*1|signal_set@0x7fffe64b8398.async_wait ^Cnum handlers 1 count 0 test_asio_sig finishing @asio|1425176930.187377|0|signal_set@0x7fffe64b8398.cancel @asio|1425176930.187411|~1| [robert@localhost misc]$ This suggests one handler was invoked which is what i might have expected. This does not have a line with >1 indicating entering the handler and there is no output from the handler and count remains at 0. Could someone help me to understand this. [ I am using Fedora 21, gcc 4.9.2, x86_64, boost 1.57 ] kind regards
On 1/03/2015 15:39, Robert Valkenburg wrote:
I don't understand why io_service.run() says 6 handlers where invoked but otherwise it seems OK.
Now if i replace io_service.run() with io_service.run_one() i expected the handler to be invoked once when CNTR C is pressed. Here is the output [...] This suggests one handler was invoked which is what i might have expected. This does not have a line with >1 indicating entering the handler and there is no output from the handler and count remains at 0.
"One handler" does not necessarily mean "one application code handler". Many high-level async operations are actually composed internally of a sequence of lower-level operations. As such, it may require multiple internal handler calls before your user-level handler is actually called. From your output, it appears that it your case it actually requires two handler calls to actually invoke your application handler. However you should not rely on this as it may change if the internals of Asio change or if some other condition in your execution environment changes. run_one() is intended to be called in a loop with other "idle" work -- but using run() is preferred whenever you can just post the extra work to the io_service anyway. Note that an async_wait is a single-shot thing anyway -- if you didn't call async_wait again in your handler then it would only catch the signal once, if that's what you're trying to do.
participants (2)
-
Gavin Lambert
-
Robert Valkenburg