Why does the asio exise expires_from_now () function override deadline_timer?

When I try to get (not set!) The current expiration time using boost expires_from_now (), it seems to actually cancel the timer, but it really works as expected, but finally does not call the handler.

Or, in other words, when accessing deadline_timer with expires_from_now (), it immediately calls the handler and does not call the handler when it expires.

Pay attention to the following code and the corresponding output:

#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) { std::cout << microsec_clock::local_time() << " Handler1: Timer 1 was cancelled or retriggered." << std::endl; } else { std::cout << microsec_clock::local_time() << " Handler1: expired." << std::endl; } } boost::asio::io_service io_service1; class Mytimer { public: Mytimer(); void startTimer(); void runTimerThread(); bool isRunning(); private: bool m_isRunning; boost::asio::deadline_timer* m_pTimer; boost::thread* m_pThread; }; Mytimer::Mytimer() : m_pTimer(NULL), m_pThread(NULL) { m_pTimer = new boost::asio::deadline_timer(io_service1); m_pTimer->async_wait(handler1); } void Mytimer::runTimerThread() { io_service1.run(); } void Mytimer::startTimer() { m_pThread = new boost::thread(&Mytimer::runTimerThread, this); m_pTimer->expires_from_now(boost::posix_time::seconds(10)); } bool Mytimer::isRunning() { time_duration td = m_pTimer->expires_from_now(); if (td.total_seconds() > 0) { return true; } return false; } int main() { time_facet *facet = new time_facet("%Y%m%d %H:%M:%S%f"); std::cout.imbue(std::locale(std::cout.getloc(), facet)); cout << microsec_clock::local_time() << " before timer construction" << endl; Mytimer timer; cout << microsec_clock::local_time() << " before startTimer()" << endl; timer.startTimer(); cout << microsec_clock::local_time() << " IsRunning: " << timer.isRunning() << endl; for (int i = 0; i <= 20; i++) { sleep(1); cout << microsec_clock::local_time() << " IsRunning: " << timer.isRunning() << endl; } } 

20120412 22: 41: 45689235 before building the timer
20120412 22: 41: 45689514 before startTimer ()
20120412 22: 41: 45689619 IsRunning: 1
20120412 22: 41: 45689693 Handler1: Timer 1 has been canceled or restarted.
20120412 22: 41: 46689792 IsRunning: 1
20120412 22: 41: 47689994 IsRunning: 1
20120412 22: 41: 48690179 IsRunning: 1
20120412 22: 41: 49690375 IsRunning: 1
20120412 22: 41: 50690530 IsRunning: 1
20120412 22: 41: 51690712 IsRunning: 1
20120412 22: 41: 52690884 IsRunning: 1
20120412 22: 41: 53691069 IsRunning: 1
20120412 22: 41: 54691236 IsRunning: 0
20120412 22: 41: 55691428 IsRunning: 0
20120412 22: 41: 56691614 IsRunning: 0
20120412 22: 41: 57691810 IsRunning: 0
20120412 22: 41: 58692001 IsRunning: 0
20120412 22: 41: 59692193 IsRunning: 0
20120412 22: 42: 00692364 IsRunning: 0
20120412 22: 42: 01692542 IsRunning: 0
20120412 22: 42: 02692706 IsRunning: 0
20120412 22: 42: 03692886 IsRunning: 0
20120412 22: 42: 04693071 IsRunning: 0
20120412 22: 42: 05693267 IsRunning: 0
20120412 22: 42: 06693465 IsRunning: 0

+7
source share
2 answers

When I try to get (not set!) The current expiration time using boost expires_from_now (), it seems to actually cancel the timer, but it actually works as expected, but finally does not call the handler.

this assumption is false. When you create your deadline_timer

 m_pTimer = new boost::asio::deadline_timer(io_service1); m_pTimer->async_wait(handler1); 

you said that it expires immediately. Then when you start your io_service

 m_pThread = new boost::thread(&Mytimer::runTimerThread, this); 

you subsequently call

 m_pTimer->expires_from_now(boost::posix_time::seconds(10)); 

which, in accordance with the documentation, describes that this will cancel any outstanding handlers, a selection is added - mine.

This function sets the expiration time. Waiting for asynchronous wait operations will be canceled . The handler for each canceled operation will be called with the error boost::asio::error::operation_aborted code.

To solve this problem, change the Mytimer::startTimer() method as follows

 --- timer4.cc.orig 2012-04-13 11:18:47.000000000 -0500 +++ timer4.cc 2012-04-13 11:16:54.000000000 -0500 @@ -1,4 +1,3 @@ - #include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/date_time/posix_time/posix_time.hpp> @@ -39,7 +38,6 @@ m_pThread(NULL) { m_pTimer = new boost::asio::deadline_timer(io_service1); - m_pTimer->async_wait(handler1); } void Mytimer::runTimerThread() @@ -49,8 +47,9 @@ void Mytimer::startTimer() { - m_pThread = new boost::thread(&Mytimer::runTimerThread, this); m_pTimer->expires_from_now(boost::posix_time::seconds(10)); + m_pTimer->async_wait(handler1); + m_pThread = new boost::thread(&Mytimer::runTimerThread, this); } bool Mytimer::isRunning() 

leading to expected behavior

 mbp:stackoverflow samm$ ./a.out 20120413 11:17:22922529 before timer construction 20120413 11:17:22923155 before startTimer() 20120413 11:17:22923530 IsRunning: 1 20120413 11:17:23924702 IsRunning: 1 20120413 11:17:24925971 IsRunning: 1 20120413 11:17:25927320 IsRunning: 1 20120413 11:17:26928715 IsRunning: 1 20120413 11:17:27929969 IsRunning: 1 20120413 11:17:28930601 IsRunning: 1 20120413 11:17:29931843 IsRunning: 1 20120413 11:17:30933098 IsRunning: 1 20120413 11:17:31934366 IsRunning: 0 20120413 11:17:32923594 Handler1: expired. 20120413 11:17:32934692 IsRunning: 0 20120413 11:17:33935922 IsRunning: 0 20120413 11:17:34936638 IsRunning: 0 20120413 11:17:35937905 IsRunning: 0 20120413 11:17:36939133 IsRunning: 0 20120413 11:17:37940407 IsRunning: 0 20120413 11:17:38941043 IsRunning: 0 20120413 11:17:39942319 IsRunning: 0 20120413 11:17:40942662 IsRunning: 0 20120413 11:17:41943989 IsRunning: 0 20120413 11:17:42945284 IsRunning: 0 20120413 11:17:43946555 IsRunning: 0 mbp:stackoverflow samm$ 
+10
source

The following code now has the correct initialization deadline_timer, and has a private flag bool, which allows you to determine if the timer is currently running. It also has a local handler.

 class Mytimer { public: Mytimer(); void startTimer(int timeDelaySecs); void cancelTimer(); void runTimerThread(); bool isRunning(); void timerHandler(const boost::system::error_code& ec); private: bool m_isRunning; boost::asio::deadline_timer* m_pTimer; boost::thread* m_pThread; }; Mytimer::Mytimer() : m_pTimer(NULL), m_pThread(NULL) { m_pTimer = new boost::asio::deadline_timer(io_service1); } void Mytimer::runTimerThread() { io_service1.run(); } void Mytimer::startTimer(int timeDelaySecs) { m_pTimer->expires_from_now(boost::posix_time::seconds(timeDelaySecs)); m_pTimer->async_wait(boost::bind(&Mytimer::timerHandler, this, _1)); m_pThread = new boost::thread(&Mytimer::runTimerThread, this); m_isRunning = true; } bool Mytimer::isRunning() { return m_isRunning; } void Mytimer::timerHandler(const boost::system::error_code& ec) { if (ec == boost::asio::error::operation_aborted) { std::cout << microsec_clock::local_time() << " Handler1: Timer 1 was cancelled or retriggered." << std::endl; } else { std::cout << microsec_clock::local_time() << " Handler1: expired." << std::endl; } m_isRunning = false; } 
+1
source

All Articles