How do you distinguish deadline_timer canceled from restarting

When you call expires_from_now() on a running timer, the timer is canceled and a new timer is called. Therefore, the associated handler is called. In the handler, it is easy to distinguish between a canceled and an expired timer. However, I am wondering if there is a way to discriminate between expired and re-timer. In both cases, the handler is called with error_code operation_aborted . Or maybe I'm missing the details.

In the code below, the following output is generated:

 20120415 21:32:28079507 Main: Timer1 set to 15 s. 20120415 21:32:28079798 Main: Timer1 set to 12 s. 20120415 21:32:28079916 Handler1: Timer 1 was cancelled or retriggered. 20120415 21:32:40079860 Handler1: expired. 

This suggests that the handler cannot implement the actions for the canceled handler, since restarting the timer will call the same handler and thereby perform the same actions. This is most likely not the intended behavior.

 #include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time_io.hpp> #include <iostream> using namespace boost::posix_time; using namespace std; void handler1(const boost::system::error_code &ec) { if (ec == boost::asio::error::operation_aborted) { cout << microsec_clock::local_time() << " Handler1: Timer was cancelled or retriggered." << endl; } else { cout << microsec_clock::local_time() << " Handler1: Timer expired." << endl; } } boost::asio::io_service io_service1; void run1() { io_service1.run(); } int main() { time_facet *facet = new time_facet("%Y%m%d %H:%M:%S%f"); cout.imbue(locale(cout.getloc(), facet)); boost::asio::deadline_timer timer1(io_service1, seconds(15)); timer1.async_wait(handler1); cout << microsec_clock::local_time() << " Main: Timer1 set to 15 s." << endl; // now actually run the timer boost::thread thread1(run1); timer1.expires_from_now(seconds(12)); cout << microsec_clock::local_time() << " Main: Timer1 set to 12 s." << endl; // here the timer is running, but we need to reset the deadline timer1.async_wait(handler1); thread1.join(); // wait for thread1 to terminate } 
+6
source share
2 answers

I suggest creating a class for the deadline_timer shell using composition. To cancel it, set the flag to remember that it was canceled. In the handler, reset the flag. When calling expires_from_now() do not set the flag.

 #include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time_io.hpp> #include <iostream> class Timer { public: Timer( const std::string& name, boost::asio::io_service& io_service ) : _name( name ), _timer( io_service ), _cancelled( false ) { _timer.expires_from_now( boost::posix_time::seconds(0) ); this->wait(); } void wait() { _timer.async_wait( boost::bind( &Timer::handler, this, boost::asio::placeholders::error ) ); } void cancel() { _cancelled = true; _timer.cancel(); } void restart() { _timer.expires_from_now( boost::posix_time::seconds(5) ); } private: void handler( const boost::system::error_code& error ) { if ( !error ) { std::cout << _name << " " << __FUNCTION__ << std::endl; _timer.expires_from_now( boost::posix_time::seconds(5) ); this->wait(); } else if ( error == boost::asio::error::operation_aborted && _cancelled ) { _cancelled = false; std::cout << _name << " " << __FUNCTION__ << " cancelled" << std::endl; } else if ( error == boost::asio::error::operation_aborted ) { std::cout << _name << " " << __FUNCTION__ << " retriggered" << std::endl; this->wait(); } else { std::cout << "other error: " << boost::system::system_error(error).what() << std::endl; } } private: const std::string _name; boost::asio::deadline_timer _timer; bool _cancelled; }; int main() { boost::asio::io_service ios; Timer timer1( "timer1", ios ); Timer timer2( "timer2", ios ); boost::thread thread( boost::bind( &boost::asio::io_service::run, boost::ref(ios) ) ); sleep( 3 ); std::cout << "cancelling" << std::endl; timer1.cancel(); timer2.restart(); thread.join(); } 

trial session

 macmini:stackoverflow samm$ ./a.out timer1 handler timer2 handler cancelling timer1 handler cancelled timer2 handler retriggered timer2 handler ^C macmini:stackoverflow samm$ 
+4
source

I don't know anything and there is probably no good way to do this (there is nothing in the documentation saying that you can separate the two situations).

I believe that this was done as intended. Setting deadline_timer to a new expiration time cancels any previous handler because:

  • sometimes it’s hard to say that something was already waiting on the timer, so it would be hard to say what exactly will happen when you set the expiration time;
  • This is an easy way to prevent scheduled events from happening twice, requiring special handling of another error code that is more error prone.
0
source

Source: https://habr.com/ru/post/913265/


All Articles