2013-10-24 42 views
0

我有这样的测试课。我想要做的就是继续在这个对象中运行三个定时器。但是在我实例化一个对象之后,有些计时器只是继续重复,但其他计时器会在3分钟后消失。任何人都可以为我解释这个吗?deadline_timer奇怪的行为

class EventProcessor 
{ 
private: 
    boost::asio::deadline_timer* m_Timer0; 
    boost::asio::deadline_timer* m_Timer1; 
    boost::asio::deadline_timer* m_Timer2; 
    boost::asio::io_service io0; 
    boost::asio::io_service io1; 
    boost::asio::io_service io2; 

    int TimerInterval[3]; 
    boost::asio::deadline_timer* Timers[3]; 
public: 
    EventProcessor(int p_0, int p_1, int p_2) 
    { 
     TimerInterval[0] = p_0; 
     TimerInterval[1] = p_1; 
     TimerInterval[2] = p_2; 

     m_Timer0= new boost::asio::deadline_timer(io0, boost::posix_time::seconds(TimerInterval[0])); 
     Timers[0] = m_Timer0; 
     m_Timer1 = new boost::asio::deadline_timer(io1, boost::posix_time::seconds(TimerInterval[1])); 
     Timers[1] = m_Timer1; 
     m_Timer2 = new boost::asio::deadline_timer(io2, boost::posix_time::seconds(TimerInterval[2])); 
     Timers[2] = m_Timer2; 
     m_Timer0->async_wait(boost::bind(&EventProcessor::HandleExpire, this, boost::asio::placeholders::error, 0)); 
     m_Timer1->async_wait(boost::bind(&EventProcessor::HandleExpire, this, boost::asio::placeholders::error, 1)); 
     m_Timer2->async_wait(boost::bind(&EventProcessor::HandleExpire, this, boost::asio::placeholders::error, 2)); 
     StartWithNewThread(0); 
     StartWithNewThread(1); 
     StartWithNewThread(2); 
    } 


private: 
    void HandleExpire(const boost::system::error_code& p_ec, int p_TimerIndex) 
    { 
     if(p_ec == boost::asio::error::operation_aborted) 
     { 
      std::cout << "Timer" << p_TimerIndex << " canceled" << std::endl; 
      return; 
     } 
     std::cout << "Timer" << p_TimerIndex << " expired" << std::endl; 
     //Reset(p_OriginalTimer, TimerInterval[p_TimerIndex], p_TimerIndex); 
     boost::thread Thread(boost::bind(&EventProcessor::Reset, this, p_TimerIndex, TimerInterval[p_TimerIndex])); 
    } 

    void Start(int p_Index) 
    { 
     boost::asio::io_service& UnderlyingIO = Timers[p_Index]->get_io_service(); 
     UnderlyingIO.reset(); 
     UnderlyingIO.run(); 
     UnderlyingIO.stop(); 
     return; 
    } 

    void StartWithNewThread(int p_Index) 
    { 
     boost::thread Thread(boost::bind(&EventProcessor::Start, this, p_Index)); 
     std::cout << Thread.get_id() << "<->" << "Timer" << p_Index << std::endl; 
     return; 
    } 

public: 
    void Reset(int p_Index, int p_Seconds) 
    { 
     Timers[p_Index]->cancel(); 
     Timers[p_Index]->expires_from_now(boost::posix_time::time_duration(0,0,p_Seconds,0)); 
     TimerInterval[p_Index] = p_Seconds; 
     Timers[p_Index]->async_wait(boost::bind(&EventProcessor::HandleExpire, this, boost::asio::placeholders::error, p_Index)); 
     boost::asio::io_service& UnderlyingIO = Timers[p_Index]->get_io_service(); 
     UnderlyingIO.reset(); 
     UnderlyingIO.run(); 
     UnderlyingIO.stop(); 
     return; 
    } 
}; 
+1

为什么每个计时器都有自己的asio服务?为什么你要为Reset启动一个新的线程(而不是只有一个线程一直运行底层IO服务?)在async_wait之后调用reset是很奇怪的(也可能是问题的根源,因为它可以删除async_wait添加的工作)。 – IdeaHat

+0

我想为三个计时器使用一个io_service,但它似乎不工作,因为我将需要启动它们并单独重置它们。 – cynric4sure

+0

我的理解是io.run()实际上是在计时器开始倒计时的时候。所以如果我需要在不同时刻启动计时器,我需要不同的io_service。是对的吗? – cynric4sure

回答

2

所以这是你应该怎么做:

#include "test.h" 
#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/atomic.hpp> 

class EventProcessor 
{ 
private: 
    std::unique_ptr<boost::asio::deadline_timer> m_Timers[3]; 

    boost::asio::io_service service; 

    boost::atomic<int> TimerInterval[3]; 

public: 
    EventProcessor(int time0,int time1, int time2) 
    { 
    TimerInterval[0] = time0; 
    TimerInterval[1] = time1; 
    TimerInterval[2] = time2; 

    for (int i = 0; i < 3; i++) 
    {   
     m_Timers[i].reset(
     new boost::asio::deadline_timer(service)); 
    } 
    } 
    ~EventProcessor() 
    { 
    service.stop(); 
    for (int i = 0; i < 3; i++) 
    { 
     m_Timers[i]->cancel(); 
    } 
    } 
    void Run() 
    { 
    for (int i = 0; i < 3; i++) 
    { 
     m_Timers[i]->expires_from_now(boost::posix_time::seconds(TimerInterval[i])); 
     m_Timers[i]->async_wait(boost::bind(&EventProcessor::HandleExpire, 
     this, 
     i, 
     _1)); 
    } 
    service.run(); 
    } 
    void RunAsync() 
    { 
    boost::thread(boost::bind(&EventProcessor::Run,this)); 
    } 
    void Reset(int i,int seconds) 
    { 
    TimerInterval[i] = seconds; 

    m_Timers[i]->expires_from_now(boost::posix_time::seconds(TimerInterval[i])); 
    m_Timers[i]->async_wait(boost::bind(&EventProcessor::HandleExpire, 
     this, 
     i, 
     _1)); 
    } 
private: 
    void HandleExpire(int p_TimerIndex, const boost::system::error_code& error) 
    { 
    if(error == boost::asio::error::operation_aborted) 
    { 
     std::cout << "Timer" << p_TimerIndex << " canceled" << std::endl; 
     return; 
    } 
    std::cout << "Timer" << p_TimerIndex << " expired" << std::endl; 
    //Reset(p_OriginalTimer, TimerInterval[p_TimerIndex], p_TimerIndex); 

    m_Timers[p_TimerIndex]->expires_from_now(
     boost::posix_time::seconds(TimerInterval[p_TimerIndex])); 
    m_Timers[p_TimerIndex]->async_wait(boost::bind(&EventProcessor::HandleExpire, 
     this, 
     p_TimerIndex, 
     _1)); 
    } 
}; 

int main() 
{ 
    EventProcessor ev(1,2,3); 
    ev.RunAsync(); 
    getchar(); 
    ev.Reset(2,4); 
    getchar(); 
} 

就算我没有任何花哨的棋子,看看您是否正在运行或不(你完全需要的,如果你希望这可以安全使用)。

您可以将boost :: asio :: io_service视为可以进行异步调用的上下文。它创建一个消息的FIFO队列来处理,并在的位置和时间将其告知。处理这些消息的最常见方法是boost :: asio :: io_service :: run,它将处理消息,直到没有任何事情可以完成。 “没有什么可以做”是一个灵活的定义:它并不一定意味着有一个信息需要处理,只需要做些事情。只要一个async_wait正在进行,直到处理程序被调用,像截止日期计时器这样的事情就可以确保有“可以完成的任务”。您可以通过创建boost :: asio :: io_service :: work实例来手动强制执行某些操作。这使得在工作对象的整个生命周期中都有“剩下的事情要做”。

截止日期计时器类负责所有的异步调用,因此您不必产生所有这些线程。 io_service执行同步,这是防止恼人的控制问题所必需的。

因此,为了与你的代码的问题:

与所有这些线程控制io_service对象,这是很难说什么是真正去错......我要猜怎么可能会错。我会把钱放在线路的某个地方,在截止日期计时器超时之前调用io_service :: cancel,这会停止循环。我在我的代码中通过在一个同步线程(io_service :: run调用)中执行所有控制(调用wait_async)来解决此问题,并且仅当我希望代码停止时才调用io_service :: cancel。

+0

谢谢。刚刚尝试了这个想法。它工作正常 – cynric4sure

+0

还有一个问题。看来这个东西不能被正确地破坏。 – cynric4sure

+0

我取消了所有的定时器,然后在我的分解器中调用io.stop(),它不起作用。看起来io.run()永远不会返回,即使我在我的分解器中调用了io.stop()。 – cynric4sure