0

Below is sample code of Timer I am using in my server. It is a multithreaded process that process loads of data. Once timer triggers it does some operation on processed data and reset itself for new time

class MyTimer
{
    public:
        MyTimer(boost::asio::io_service& ios):strand_(ios)
        {
            for (int i = 0; i < 10; i++)
            {
                std::auto_ptr<boost::thread> thread(
                        new boost::thread(boost::bind(&boost::asio::io_service::run,
                                          &ios_)));
                thread_pool_.push_back(thread.get());
                thread.release();
            }
            boost::posix_time::seconds expTime(10);
            eodTimer_.reset(new boost::asio::deadline_timer(ios));
            eodTimer_->expires_from_now(expTime);
            eodTimer_->async_wait(boost::bind(&MyTimer::onTimer, this));
        };

         ~MyTimer()
         {
              ThreadPool::iterator it(thread_pool_.begin());
              for (; it != thread_pool_.end(); ++it)
              {
                   (*it)->join();
                   delete *it;
               }
         }
        void onTimer()
        {
            //do some stuff...
            // reset timer
            boost::posix_time::seconds expTime(10);
            eodTimer_->expires_from_now(expTime);
            eodTimer_->async_wait(boost::bind(&MyTimer::onTimer, this));
        }

    private:
        boost::asio::io_service ios;
        boost::asio::strand strand_;
        boost::scoped_ptr<boost::asio::deadline_timer> eodTimer_;
};

So far I do not see any issue with this code. But after running from some hours my Server crashes. Stack trace points me to ::onTimer callback handler.

#0  0x0a446c06 in boost::asio::detail::timer_queue<boost::asio::time_traits<boost::posix_time::ptime> >::cancel_timer (this=0xe3be0bc,
    timer_token=0xe9877ec) at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/detail/timer_queue.hpp:141
#1  0x0a445791 in boost::asio::detail::epoll_reactor<false>::cancel_timer<boost::asio::time_traits<boost::posix_time::ptime> > (this=0xe49f498,
        timer_queue=..., token=0xe9877ec) at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/detail/epoll_reactor.hpp:424
#2  0x0a444197 in boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::detail::               epoll_reactor<false> >::cancel (this=0xe3be0a8, impl=..., ec=...) at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/detail/deadline_timer_service.hpp:104    #3  0x0a443f31 in boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::detail::               epoll_reactor<false> >::expires_at (this=0xe3be0a8, impl=..., expiry_time=..., ec=...)
            at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/detail/deadline_timer_service.hpp:120
#4  0x0a441e92 in boost::asio::detail::deadline_timer_service<boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::detail::               epoll_reactor<false> >::expires_from_now (this=0xe3be0a8, impl=..., expiry_time=..., ec=...)
                at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/detail/deadline_timer_service.hpp:137
#5  0x0a43f895 in boost::asio::deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> >::                expires_from_now (
                    this=0xe49f438, impl=..., expiry_time=..., ec=...) at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/deadline_timer_service.hpp: 144
#6  0x0a451d64 in boost::asio::basic_deadline_timer<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime>, boost::asio::       deadline_timer_service<boost::posix_time::ptime, boost::asio::time_traits<boost::posix_time::ptime> > >::expires_from_now (this=0xe9877e8, expiry_time=...)
                        at /vobs/FO_FOX/fo_fx_appl/appl/include/boost/asio/basic_deadline_timer.hpp:297
#7  0x0a44e941 in fxpay::AggregatorRouter::Impl::MyTimer::onTimer (this=0xe987e48) at MyTimer.cpp:183

Is there something wrong the way I am using boost::dead_line timer? (I am using 1.39 boost version)

sehe
  • 374,641
  • 47
  • 450
  • 633
user1545583
  • 69
  • 1
  • 6

1 Answers1

1

You're running 10 threads and there is no synchronization of access to eodTimer.

The deadline_timer object is not threadsafe, so you get Undefined Behaviour because of the data race.

Did you mean to run the timer on a strand?

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I am using strand to process some other asio tasks that execute at high frequency. For sake of simpliciy I have not copied code. In this case timer expires after 24 hours and resets again to 24Hrs in handler. And there is only one timer object. I am not sure if there is in possibility of race condition for timer. Correct me if I am wrong. – user1545583 Feb 09 '15 at 07:00
  • Not if the timer is not accessed from any of the other strands. In that case, you're likely having a data race when _"it does some operation on processed data"_. But then we cannot tell because the relevant code is not there. – sehe Feb 09 '15 at 08:54
  • I forgot to mention earlier, which I should have. In above stack trace, when I check for number of elements in boost::asio::detail::timer_queue, I see number of object queued as '92', which is quite strange, as timer resets after 24 hours and process is running for many days. All objects were corrupt. Does anyone observed such behaviour earlier? – user1545583 Feb 10 '15 at 04:05
  • "All objects were corrupt". I find this a strange claim. How can you tell? Since you're expecting to use only 1 timer, wouldn't you necessarily expect the objects to be uninitialized? That would make that uninteresting. If you want to debug/learn about the inmemory representation, start with a known working program (without Undefined Behaviour) and debug that with optimizations disabled. Then you can start reasoning about such things (unless, you're the author of the timer service in Asio) – sehe Feb 10 '15 at 08:13