【问题标题】:resetting boost::deadline_timer in handler causing crash在处理程序中重置 boost::deadline_timer 导致崩溃
【发布时间】:2015-02-06 12:25:35
【问题描述】:

以下是我在服务器中使用的计时器的示例代码。它是一个处理大量数据的多线程进程。一旦定时器触发,它就会对处理过的数据进行一些操作,并在新的时间自行重置

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_;
};

到目前为止,我没有看到此代码有任何问题。但是在运行几个小时后,我的服务器崩溃了。堆栈跟踪将我指向 ::onTimer 回调处理程序。

#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

我使用 boost::dead_line 计时器的方式有问题吗? (我用的是1.39 boost版本)

【问题讨论】:

    标签: boost-asio boost-thread


    【解决方案1】:

    您正在运行 10 个线程,并且没有同步访问 eodTimer

    deadline_timer 对象不是线程安全的,因此您会因为数据竞争而获得未定义行为。

    您的意思是在链上运行计时器吗?

    【讨论】:

    • 我正在使用 strand 处理其他一些高频执行的 asio 任务。为了简单起见,我没有复制代码。在这种情况下,计时器在 24 小时后到期,并在处理程序中再次重置为 24Hrs。而且只有一个计时器对象。我不确定计时器是否存在竞争条件。如果我错了,请纠正我。
    • 如果没有从任何其他链访问计时器,则不会。在这种情况下,当“它对已处理的数据执行一些操作” 时,您可能会遇到数据竞争。但后来我们无法判断,因为相关代码不存在。
    • 我之前忘了提,我应该提的。在上面的堆栈跟踪中,当我检查 boost::asio::detail::timer_queue 中的元素数量时,我看到排队的对象数量为“92”,这很奇怪,因为计时器在 24 小时后重置并且进程正在运行很多天。所有对象都已损坏。之前有人观察到这种行为吗?
    • “所有对象都已损坏”。我觉得这是一个奇怪的说法。你怎么知道?由于您希望只使用 1 个计时器,您是否一定希望对象未初始化?那会让那变得无趣。如果您想调试/了解内存表示,请从已知的工作程序(没有未定义行为)开始,并在禁用优化的情况下对其进行调试。然后你就可以开始推理这些事情了(除非你是 Asio 中定时器服务的作者)
    猜你喜欢
    • 1970-01-01
    • 2013-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2011-04-02
    • 2015-06-28
    • 1970-01-01
    相关资源
    最近更新 更多