[asio] deadline_timer callback is not called
Hi, I've yet posted a question about this topic but I not solve, so I try to ask again. PS: I used the same solution (in conjunction with asio::serial_port) in another project and, there, it works! I'm working on a library and I have only one static io_service and io_service::work like in the following code: ---------------------- START CODE ------------------------ typedef boost::shared_ptrboost::asio::io_service::work io_work_ptr; // Main io_service static boost::asio::io_service io_service; static boost::scoped_ptrboost::thread io_service_thread; static io_work_ptr p_work; static bool thread_started; void io_worker_thread(void) { #if(WIN32 && _WIN32_DCOM) struct com_init { com_init() { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); } ~com_init() { CoUninitialize(); } } initializer_object; #endif io_service.run(); }; bool CreateMainThread() { if (!thread_started) { try { // create the work object on the heap: // [Reference counting] // This object is a simple pointer because // it is assigned to each created objects // These objects store it in a shared_ptr so, // when the last object is destroyed // The io_service::work is destroyed as well p_work.reset( new boost::asio::io_service::work(io_service) ); // Instead of start the worker thread directly by // passing the io_service object, // I call the io_worker_thread function where // I can do some initialization tasks like // calling CoInitializeEx for COM io_service_thread.reset(new boost::thread(io_worker_thread)); thread_started = !thread_started; return true; } catch (boost::thread_resource_error e) { // Failed to create the new thread return false; } } else return true; } /*! * \brief Factory function for AudioPlayer objects creation */ EXTERN_C EUROAUDIOLIB_API AudioPlayerHndl CALL CreateAudioPlayer() { if (!CreateMainThread()) return NULL; // create the new object AudioPlayer* pAudioPlayer = new AudioPlayer; pAudioPlayer->io_worker_ptr = p_work; return pAudioPlayer; }; ---------------------- END CODE ------------------------ In the above code pAudioPlayer->io_worker_ptr is declared as: io_work_ptr p_work; In a class I have to use the timer, so I initialize it with the global io_service object: ---------------------- START CODE ------------------------ boost::asio::deadline_timer rx_timer_; WaveStream::WaveStream() : rx_timer_(io_service) { }; void WaveStream::ProcessRTPPacket() { // RTP Packet received ...... //Start a new timer or renew it rx_timer_.expires_from_now( boost::posix_time::milliseconds( 1000 ) ); io_service.reset(); // We managed to cancel the timer. Start new asynchronous wait. rx_timer_.async_wait( boost::bind(&WaveStream::handle_timeout, this, _1) ); .... } void WaveStream::handle_timeout(const boost::system::error_code& error) { std::cout << "BOOST TIMER RAISED!!" << endl; // A Timeout is raised: a stream is end if (!error) {...} }; ---------------------- END CODE ------------------------ But the callbak is never called!! Since ProcessRTPPacket is called frequently, I try also to move the timer on another point just for test with the same effect! Where could be the mistake? Thanks in advance! Daniele.
Igor R ha scritto:
io_service.run(); Put some debug message here, to see when the io_service::run ends.
Hi Igor, thanks for you reply. I've put some debug code: ---------------------- START CODE ------------------------ void io_worker_thread(void) { io_service.run(); std::cout << ">>>> io_service.run() TERMINATED! <<<<" << endl; }; ---------------------- END CODE ------------------------ And the io_service.run() never returns, neither at the end of the application. This was caused because I had declared the io_service::work* like a shared_ptr. I change its declaration to simply: static boost::asio::io_service::work* p_work; And now io_service.run() ends only at the application end. So, when I call the timer, the io_service should run!! I try to add a call to io_service.run() after the timer async_wait: ---------------------- START CODE ------------------------ { ..... //Start a new timer or renew it rx_timer_.expires_from_now( boost::posix_time::milliseconds( 2000 ) ); // We managed to cancel the timer. Start new asynchronous wait. rx_timer_.async_wait( boost::bind(&WaveStream::handle_timeout, this, _1) ); io_service.run(); std::cout << "io_service.run() called " << endl; } void WaveStream::handle_timeout(const boost::system::error_code& error) { std::cout << "BOOST TIMER RAISED!!" << endl; }; ---------------------- END CODE ------------------------ ..and in this manner the callback is called immediately after the io_service.run() without waiting and in output I see: BOOST TIMER RAISED!! io_service.run() called BOOST TIMER RAISED!! io_service.run() called BOOST TIMER RAISED!! io_service.run() called BOOST TIMER RAISED!! io_service.run() called BOOST TIMER RAISED!! Suggestions? Daniele.
Igor R ha scritto:
I try to add a call to io_service.run() after the timer async_wait:
Why? You already run io_service within io_worker_thread(), don't you? What you have to do is just: ...expires_from_now(...); ...async_wait(...);
It was only a test, also doing so the first io_service.run() does not returns! Ok, Using only ...expires_from_now(...); ...async_wait(...); I don't know why but...it doesn't work! Also I don't know why in the other project it works! The only difference is that, in the other project, I used boost_1_39_0 (while in this one I use boost_1_40_0) and I calling the timers inside the asio::serial_port::async_read_some callback! I know that is quite difficult for you to help me not knowing the code, but.. How could cause this kind of behavior? Thanks, Daniele
How could cause this kind of behavior?
Another guess: do you call the timer functions (expires_from_now(), async_wait() ) from the thread that is running io_service or from another one? That is, who calls ProcessRTPPacket() function? If it's called from another thread, can you try the following: // instead of calling expires_from_now(), async_wait() directly... yourTimer_.get_io_service().post(boost::bind(&WaveStream::setTimer, this)); //... void setTimer() { // Some debug message, to see if the function is called. ...expires_from_now(...); ...async_wait(...); } Now see if setTimer is called. If it's not called, you've got some problem with your io_service - it's not running properly.
Igor R ha scritto:
How could cause this kind of behavior?
Another guess: do you call the timer functions (expires_from_now(), async_wait() ) from the thread that is running io_service or from another one? That is, who calls ProcessRTPPacket() function? If it's called from another thread, can you try the following:
No, from another one. The thread that run the io_service simply runs it: void io_worker_thread(void) { io_service.run(); std::cout << ">>> io_service.run() TERMINATED! <<<<<" << endl; }; ProcessRTPPacket() is a library "event" and maybe it is called from another thread! Mmmm...so maybe, in the other project, it worked because I called timers into the asio::serial_port::async_read_some callback that should be inside the io_service thread! Isn't it?
// instead of calling expires_from_now(), async_wait() directly... yourTimer_.get_io_service().post(boost::bind(&WaveStream::setTimer, this)); //...
void setTimer() { // Some debug message, to see if the function is called. ...expires_from_now(...); ...async_wait(...); }
Now see if setTimer is called.
Yes, the setTimer is called, but the timer callback not! Cheers, Daniele.
Mmmm...so maybe, in the other project, it worked because I called timers into the asio::serial_port::async_read_some callback that should be inside the io_service thread! Isn't it?
asio::deadline_timer is not thread-safe, so you're not allowed to access it from multiple threads. Since it's being processed by the io_service from within its thread, you have to post any timer method to the io_service (as far as I understand).
Yes, the setTimer is called, but the timer callback not!
You call expires_from_now and async_wait from setTimer(), and the handler is not called? Well, that's weird. Ensure you pass reasonable time duration. Try to use the overload that returns an error: boost::system::error_code er; expires_from_now(seconds(1), er); What does it return in "er"?
Igor R ha scritto:
Yes, the setTimer is called, but the timer callback not!
You call expires_from_now and async_wait from setTimer(), and the handler is not called? Well, that's weird. Ensure you pass reasonable time duration. Try to use the overload that returns an error: boost::system::error_code er; expires_from_now(seconds(1), er);
Oh, I'm sorry. It was my fault. I forgot to remove a call, all these test make me crazy!! :-P Calling: rx_timer_.get_io_service().post(boost::bind(&WaveStream::StartTimer, this)); the StartTimer is not called!!! So... The io_service should be running but the post() does not work so, what can I check? Thanks for the support! Daniele.
the StartTimer is not called!!!
So... The io_service should be running but the post() does not work so, what can I check?
Probably, some handler (called by io_service) blocks? Check all the stuff, which is called directly or indirectly from within the handlers -- remember that if one of your handlers blocks, the other once won't have a chance to run.
Igor R ha scritto:
Probably, some handler (called by io_service) blocks? Check all the stuff, which is called directly or indirectly from within the handlers -- remember that if one of your handlers blocks, the other once won't have a chance to run.
Mmm...I do nothing more than: 1- Create a io_service::work on the heap; 2- Create a new Thread; 3- Call the io_service.run() within this new thread; 4- Assign the io_service::work* to a boost::shared_ptr; 5- Use the timer we discuss; No other io_service use! For now I discard the deadline timer "option" and I create a custom timer with a Thread and Sleep! :-( If u have other suggestions, are welcome! Thanks a lot, Daniele.
Mmm...I do nothing more than: 1- Create a io_service::work on the heap; 2- Create a new Thread; 3- Call the io_service.run() within this new thread; 4- Assign the io_service::work* to a boost::shared_ptr; 5- Use the timer we discuss; Well, if your code that simple, you can extract a minimal reproducing excerpt and post it here - then other people will be able to try and debug it. Just remove anything unrelated to the timer problem (maybe after you do this, the problem will disappear :) ).
If u have other suggestions, are welcome!
I never encountered such a problem. It seems that your io_service dosn't work properly, but why it happens, I don't know.
participants (2)
-
Daniele Barzotti
-
Igor R