
Hi all, I started playing with ASIO timers and after scanning through the relevant docs, I set up a small case. Please find below the code snippet. The IntervalEvent class is supposed to fire the event provided on the construction at a frequency equal to the durationInterval. Somehow the code below fails to compile on VC7.1. I am getting several warnings and the error: c:\program files\boost\boost_1_38\boost\mem_fn.hpp(343) : error C4716: 'boost::_mfi::dm<void __thiscall IntervalEvent::(boost::system::error_code &),IntervalEvent>::operator()' : must return a value I have not tried yet gcc. Probably I am doing something stupid. Any ideas? Further to that, I am wondering, in principle should I cancel the deadline_timer on the destructor of the IntervalEvent class? Does the io_service class know when any of the deadline_timers that is being registered goes out of scope? Thank you very much in advance. Any help would be highly appreciated. Kimon #include <boost/function.hpp> #include <iostream> #include <boost/asio.hpp> #include <boost/thread.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> class Counter { public: Counter():m_value(0) { } void onIncrement() { ++m_value; std::cout<<"Counter is "<<m_value<<std::endl; } protected: int m_value; }; class IntervalEvent { public: IntervalEvent(boost::asio::io_service &io, long durationSeconds, boost::function<void(void)> event): m_intervalDuration(durationSeconds), m_timer(io,boost::posix_time::seconds(m_intervalDuration)), m_event(event) { //io_service::run is running in only one thread m_timer.async_wait(boost::bind(&IntervalEvent::handler, this)); } ~IntervalEvent() { //should I call m_timer.cancel to notify the io_service? } void handler(boost::system::error_code& error) { if(error!= boost::asio::error::operation_aborted) { m_event(); reset(m_intervalDuration); } } void reset(long duration) { if (m_timer.expires_from_now(boost::posix_time::seconds(duration)) > 0) { m_intervalDuration = duration; //reset the async wait m_timer.async_wait(boost::bind(&IntervalEvent::handler, this)); } else { //Timer already canceled } } void cancel() { m_timer.cancel(); } size_t getCurrentInterval() const { return m_intervalDuration; } protected: long m_intervalDuration; boost::asio::deadline_timer m_timer; boost::function<void(void)> m_event; }; int main() { boost::asio::io_service io; boost::shared_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(io)); boost::thread ioservice_thread(boost::bind(&boost::asio::io_service::run, &io)); std::vector<boost::shared_ptr<IntervalEvent> > events; Counter count; long duration = 1; boost::shared_ptr<IntervalEvent> firstEvent(new IntervalEvent(io, duration, boost::bind(&Counter::onIncrement,boost::ref(count) )) ); events.push_back(firstEvent); char response = 'N'; while(response == 'N') { std::cout<<"Create a new interval event? [Y/N]"<<std::endl; std::cin>>response; if(response == 'Y') { boost::shared_ptr<IntervalEvent> test(new IntervalEvent(io, duration, boost::bind(&Counter::onIncrement,boost::ref(count) )) ); events.push_back(test); } } //cancel interval events for(std::vector<boost::shared_ptr<IntervalEvent> >::iterator it = events.begin(), itEnd = events.end(); it!=itEnd; ++it) { (*it)->cancel(); } //reset ioservice_work work.reset(); ioservice_thread.join(); return 0; }

m_timer.async_wait(boost::bind(&IntervalEvent::handler, this));
should be: m_timer.async_wait(boost::bind(&IntervalEvent::handler, this, _1)); or: m_timer.async_wait(boost::bind(&IntervalEvent::handler, this, boost::asio::placeholders::error));
void handler(boost::system::error_code& error)
should be: void handler(cosnt boost::system::error_code& error)
Further to that, I am wondering, in principle should I cancel the deadline_timer on the destructor of the IntervalEvent class? Does the io_service class know when any of the deadline_timers that is being registered goes out of scope?
On destruction, the timer cancels itself anyway. By the way, you access the timers both from main() and from another thread - which is illegal, since the asio objects are not thread-safe (except for io_service).

Thank you very much Igor. I acknowledge my ignorence regarding the thread safety issues involved, so I would like dig a little bit deeper here, if you do not mind. If there is a point in the docs that I should be looking and that I have not my apologies. I would appreciate it if you could point me there. Most of the examples that I have come across for timers have as a precondition that the io_service::run function has been invoked yet; reseting the timer happens withing the timer handler in general. I am wondering what are the issues involved when calling deadline_timer::async_wait, deadline_timer::cancel for a timer that is associated with an io_service object when io_service::run has already started in a different thread? Or in other words following the point "* the io_service may be being run in a background thread that is launched prior to the application's asynchronous operations*" in http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/reference/io_servic..., how do I launch asynch operations using an io_service that has already being run? This is relevant to what I really want to do which is: 1.Start io_service::run in one background thread 2.Start async timers on demand from the main thread that should be executed on the io_service::run thread. These timers will be associated with an event that will trigger a thread safe handler on a registerd observer(in this case the Counter class). 3. Modify/cancel from the main thread timers that have outstanding async operations in the io_service::run thread. In the particular example below, the member function onIncrement of the class Counter is not thread safe, but since the io_service::run is running on a one thread, only one handler will be invoked on the thread that runs io_service::run, so implicitly there is a serialization of access, correct? My question is what is the best practice, in order to achieve 2 and 3 above? Suprisingly, after building my toy case with your help, the effect is what I expected, but I admit that your comment made me realize that I still need to dig further in order to understand all the issues involved. I would be grateful for any comment or suggestion. Thanks a lot. Kimon On Sat, Apr 25, 2009 at 8:38 PM, Igor R <boost.lists@gmail.com> wrote:
m_timer.async_wait(boost::bind(&IntervalEvent::handler, this));
should be: m_timer.async_wait(boost::bind(&IntervalEvent::handler, this, _1)); or: m_timer.async_wait(boost::bind(&IntervalEvent::handler, this, boost::asio::placeholders::error));
void handler(boost::system::error_code& error)
should be: void handler(cosnt boost::system::error_code& error)
Further to that, I am wondering, in principle should I cancel the deadline_timer on the destructor of the IntervalEvent class? Does the io_service class know when any of the deadline_timers that is being registered goes out of scope?
On destruction, the timer cancels itself anyway.
By the way, you access the timers both from main() and from another thread - which is illegal, since the asio objects are not thread-safe (except for io_service). _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Hi all, I changed the implementation(please find it attached) so any change in the timers is forwarded through a io_service::post call to a protected handler. It works and it looks to me that there are no real thread safety issues. Can anybody confirm my understanding? Also I am wondering should the initiazation of an async_wait be forwarded through io_service::post on the first time that a deadline_timer is set for an io_service that is running on a different thread? Here http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/reference/basic_dea..., is stated that " *Invocation of the handler will be performed in a manner equivalent to using boost::asio::io_service::post().* ". Any comments or suggestions are more than welcome. Thank you Kimon Please find attached the new implementation. My understanding is that io_service::post gives the strongest guarantee that the handler will be invoked in the On Sun, Apr 26, 2009 at 12:22 AM, Kimon Simons <kimon.simons@gmail.com>wrote:
Thank you very much Igor.
I acknowledge my ignorence regarding the thread safety issues involved, so I would like dig a little bit deeper here, if you do not mind. If there is a point in the docs that I should be looking and that I have not my apologies. I would appreciate it if you could point me there.
Most of the examples that I have come across for timers have as a precondition that the io_service::run function has been invoked yet; reseting the timer happens withing the timer handler in general. I am wondering what are the issues involved when calling deadline_timer::async_wait, deadline_timer::cancel for a timer that is associated with an io_service object when io_service::run has already started in a different thread? Or in other words following the point "*the io_service may be being run in a background thread that is launched prior to the application's asynchronous operations*" in http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/reference/io_servic..., how do I launch asynch operations using an io_service that has already being run?
This is relevant to what I really want to do which is:
1.Start io_service::run in one background thread 2.Start async timers on demand from the main thread that should be executed on the io_service::run thread. These timers will be associated with an event that will trigger a thread safe handler on a registerd observer(in this case the Counter class). 3. Modify/cancel from the main thread timers that have outstanding async operations in the io_service::run thread.
In the particular example below, the member function onIncrement of the class Counter is not thread safe, but since the io_service::run is running on a one thread, only one handler will be invoked on the thread that runs io_service::run, so implicitly there is a serialization of access, correct?
My question is what is the best practice, in order to achieve 2 and 3 above? Suprisingly, after building my toy case with your help, the effect is what I expected, but I admit that your comment made me realize that I still need to dig further in order to understand all the issues involved.
I would be grateful for any comment or suggestion.
Thanks a lot.
Kimon
On Sat, Apr 25, 2009 at 8:38 PM, Igor R <boost.lists@gmail.com> wrote:
m_timer.async_wait(boost::bind(&IntervalEvent::handler, this));
should be: m_timer.async_wait(boost::bind(&IntervalEvent::handler, this, _1)); or: m_timer.async_wait(boost::bind(&IntervalEvent::handler, this, boost::asio::placeholders::error));
void handler(boost::system::error_code& error)
should be: void handler(cosnt boost::system::error_code& error)
Further to that, I am wondering, in principle should I cancel the deadline_timer on the destructor of the IntervalEvent class? Does the io_service class know when any of the deadline_timers that is being registered goes out of scope?
On destruction, the timer cancels itself anyway.
By the way, you access the timers both from main() and from another thread - which is illegal, since the asio objects are not thread-safe (except for io_service). _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

I am wondering what are the issues involved when calling deadline_timer::async_wait, deadline_timer::cancel for a timer that is associated with an io_service object when io_service::run has already started in a different thread? Or in other words following the point " the io_service may be being run in a background thread that is launched prior to the application's asynchronous operations" in http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/reference/io_servic..., how do I launch asynch operations using an io_service that has already being run?
Since the io_service itself is thread-safe, there's no problem to attach asio objects to it from another thread. I.e., you can create deadline_timer's from within the main thread, just like you do in your code. However, cancelling the timers might cause race-condition, because io_service's thread might try to access the timer at the very same moment. To avoid this you can apply the pattern, which is widely used in asio examples: private: void IntervalEvent::syncCancel() { m_timer.cancel(); } public: void IntervalEvent::cancel() { // m_timer.cancel(); instead of cancelling here, just re-post this action to io_service thread(s) // invoke another member function, in case of a complex action m_timer.get_io_service().post(bind(&IntervalEvent::syncCancel, this)); // or, in case of simple action, just construct it on-the-fly: m_timer.get_io_service().post(bind(&deadline_timer::cancel, boost::ref(m_timer))); } Any access to a running timer/socket can be made this way. As for initial async_wait(), I can't see any potential race-conditions, so I guess it's ok to do this from the main thread.
In the particular example below, the member function onIncrement of the class Counter is not thread safe, but since the io_service::run is running on a one thread, only one handler will be invoked on the thread that runs io_service::run, so implicitly there is a serialization of access, correct?
Counter::onIncrement is invoked from one thread, that's true. But writing there to std::cout is not thread-safe anyway, because std::cout is not exclusively owned by Counter.
participants (2)
-
Igor R
-
Kimon Simons