你如何区分被取消的触发式提升deadline_timer

时间:2012-04-15 19:36:04

标签: c++ boost boost-asio

在正在运行的计时器上调用expires_from_now()时, 计时器被取消,并调用一个新的计时器。 因此调用关联的处理程序。 在处理程序中很容易区分 已取消和已过期的计时器之间。 然而,我想知道,如果有一种方法可以区别对待 在过期和重新触发的计时器之间。 在这两个实例中都调用了处理程序 使用error_code operation_aborted。 或许我错过了一些细节。

以下代码生成以下输出:

20120415 21:32:28079507 Main: Timer1 set to 15 s.    
20120415 21:32:28079798 Main: Timer1 set to 12 s.    
20120415 21:32:28079916 Handler1: Timer 1 was cancelled or retriggered.    
20120415 21:32:40079860 Handler1: expired.

这表明处理程序无法实现 取消处理程序的操作,因为重新触发计时器将调用相同的处理程序,从而执行相同的操作。这可能不是预期的行为。

#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <iostream> 

using namespace boost::posix_time;
using namespace std;

void handler1(const boost::system::error_code &ec) 
{ 
    if (ec == boost::asio::error::operation_aborted)
    {
        cout << microsec_clock::local_time() << " Handler1: Timer was cancelled or retriggered." << endl; 
    }
    else
    {
        cout << microsec_clock::local_time() << " Handler1: Timer expired." << endl; 
    }
} 

boost::asio::io_service io_service1; 

void run1() 
{ 
    io_service1.run(); 
} 

int main() 
{ 
    time_facet *facet = new time_facet("%Y%m%d %H:%M:%S%f");
    cout.imbue(locale(cout.getloc(), facet));

    boost::asio::deadline_timer timer1(io_service1, seconds(15)); 
    timer1.async_wait(handler1); 
    cout << microsec_clock::local_time() << " Main: Timer1 set to 15 s." << endl; 
    // now actually run the timer
    boost::thread thread1(run1); 
    timer1.expires_from_now(seconds(12));
    cout << microsec_clock::local_time() << " Main: Timer1 set to 12 s." << endl; 
    // here the timer is running, but we need to reset the deadline
    timer1.async_wait(handler1); 
    thread1.join();   // wait for thread1 to terminate 
} 

2 个答案:

答案 0 :(得分:4)

我建议使用合成创建一个包装deadline_timer的类。取消它时,设置一个标志以记住它已被取消。在处理程序中,重置标志。调用expires_from_now()时不要设置标志。

#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <iostream> 

class Timer
{
public:
    Timer(
            const std::string& name,
            boost::asio::io_service& io_service
         ) :
        _name( name ),
        _timer( io_service ),
        _cancelled( false )
    {
        _timer.expires_from_now( boost::posix_time::seconds(0) );
        this->wait();
    }

    void wait()
    {
        _timer.async_wait(
                boost::bind(
                    &Timer::handler,
                    this,
                    boost::asio::placeholders::error
                    )
                );
    }

    void cancel() { 
        _cancelled = true;
        _timer.cancel(); 
    }

    void restart() {
        _timer.expires_from_now( boost::posix_time::seconds(5) );
    }

private:
    void handler(
            const boost::system::error_code& error
            )
    {
        if ( !error ) {
            std::cout << _name << " " << __FUNCTION__ << std::endl;
            _timer.expires_from_now( boost::posix_time::seconds(5) );
            this->wait();
        } else if ( error == boost::asio::error::operation_aborted && _cancelled ) {
            _cancelled = false;
            std::cout << _name << " " << __FUNCTION__ << " cancelled" << std::endl;
        } else if ( error == boost::asio::error::operation_aborted ) {
            std::cout  << _name << " " << __FUNCTION__ << " retriggered" << std::endl;
            this->wait();
        } else {
            std::cout << "other error: " << boost::system::system_error(error).what() << std::endl;
        }
    }

private:
    const std::string _name;
    boost::asio::deadline_timer _timer;
    bool _cancelled;
};

int
main()
{
    boost::asio::io_service ios;
    Timer timer1( "timer1", ios );
    Timer timer2( "timer2", ios );

    boost::thread thread(
            boost::bind(
                &boost::asio::io_service::run,
                boost::ref(ios)
                )
            );

    sleep( 3 );
    std::cout << "cancelling" << std::endl;
    timer1.cancel();
    timer2.restart();

    thread.join();
}

示例会话

macmini:stackoverflow samm$ ./a.out
timer1 handler
timer2 handler
cancelling
timer1 handler cancelled
timer2 handler retriggered
timer2 handler
^C
macmini:stackoverflow samm$ 

答案 1 :(得分:0)

我不知道任何方式,可能没有好办法(文档中没有任何内容说你可以分辨这两种情况)。

我相信这是出于目的。将deadline_timer设置为新的到期时间,取消之前的任何处理程序,因为:

  • 有时候很难判断某些东西是否已经在等待计时器,因此当你设定一个到期时间时,很难说出究竟会发生什么;
  • 这是一种简单的方法来防止被绑定事件运行两次,需要以特殊方式处理另一个错误代码更容易出错。