Linux 为什么 boost asio 函数 expires_from_now() 取消了deadline_timer?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10131531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:45:35  来源:igfitidea点击:

Why does boost asio function expires_from_now() cancel a deadline_timer?

c++linuxboostboost-asio

提问by Michael Hilbert

When I try to get (not set!) the current expiry time using boost expires_from_now() is seems to actually cancel the timer, yet it actually runs as expected, but does finally not call the handler.

当我尝试使用 boost expires_from_now() 获取(未设置!)当前到期时间时,似乎实际上取消了计时器,但它实际上按预期运行,但最终没有调用处理程序。

Or put in other words, when accessing a deadline_timer with expires_from_now() it will call the handler immediately and not call the handler when it expires.

或者换句话说,当使用 expires_from_now() 访问deadline_timer 时,它将立即调用处理程序,并且在它到期时不调用处理程序。

Please consider the following code and corresponding output:

请考虑以下代码和相应的输出:

#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)
    {
        std::cout << microsec_clock::local_time() << " Handler1: Timer 1 was cancelled or retriggered." << std::endl; 
    }
    else
    {
        std::cout << microsec_clock::local_time() << " Handler1: expired." << std::endl; 
    }
} 

boost::asio::io_service io_service1; 

class Mytimer {
public:
    Mytimer();
    void startTimer();
    void runTimerThread();
    bool isRunning();
private:
    bool m_isRunning;
    boost::asio::deadline_timer* m_pTimer;
    boost::thread* m_pThread;
};

Mytimer::Mytimer()
  : m_pTimer(NULL),
    m_pThread(NULL)
{
    m_pTimer = new boost::asio::deadline_timer(io_service1); 
    m_pTimer->async_wait(handler1); 
}

void Mytimer::runTimerThread()
{
    io_service1.run();
}

void Mytimer::startTimer()
{
    m_pThread = new boost::thread(&Mytimer::runTimerThread, this);
    m_pTimer->expires_from_now(boost::posix_time::seconds(10));
}

bool Mytimer::isRunning()
{

    time_duration td = m_pTimer->expires_from_now();
    if (td.total_seconds() > 0)
    {
        return true;
    }
    return false;
}

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

    cout << microsec_clock::local_time() << " before timer construction" << endl;
    Mytimer timer;
    cout << microsec_clock::local_time() << " before startTimer()" << endl;
    timer.startTimer();
    cout << microsec_clock::local_time() << " IsRunning: " << timer.isRunning() << endl;
    for (int i = 0; i <= 20; i++)
    {
        sleep(1);
        cout << microsec_clock::local_time() << " IsRunning: " << timer.isRunning() << endl;
    }
} 

20120412 22:41:45689235 before timer construction
20120412 22:41:45689514 before startTimer()
20120412 22:41:45689619 IsRunning: 1
20120412 22:41:45689693 Handler1: Timer 1 was cancelled or retriggered.
20120412 22:41:46689792 IsRunning: 1
20120412 22:41:47689994 IsRunning: 1
20120412 22:41:48690179 IsRunning: 1
20120412 22:41:49690375 IsRunning: 1
20120412 22:41:50690530 IsRunning: 1
20120412 22:41:51690712 IsRunning: 1
20120412 22:41:52690884 IsRunning: 1
20120412 22:41:53691069 IsRunning: 1
20120412 22:41:54691236 IsRunning: 0
20120412 22:41:55691428 IsRunning: 0
20120412 22:41:56691614 IsRunning: 0
20120412 22:41:57691810 IsRunning: 0
20120412 22:41:58692001 IsRunning: 0
20120412 22:41:59692193 IsRunning: 0
20120412 22:42:00692364 IsRunning: 0
20120412 22:42:01692542 IsRunning: 0
20120412 22:42:02692706 IsRunning: 0
20120412 22:42:03692886 IsRunning: 0
20120412 22:42:04693071 IsRunning: 0
20120412 22:42:05693267 IsRunning: 0
20120412 22:42:06693465 IsRunning: 0

20120412 22:41:45689235 定时器构建前
20120412 22:41:45689514 startTimer() 前
20120412 22:41:45689619 IsRunning: 1
201204416 取消201204416 处理程序 3 r 3 r 3 r 4 1 9 4 1 9 16
20120412 22:41:46689792 IsRunning:1
20120412 22:41:47689994 IsRunning:1
20120412 22:41:48690179 IsRunning:1
20120412 22:41:49690375 IsRunning:1
20120412 22:41:50690530 IsRunning:1
20120412 22点41: 51690712 IsRunning:1
20120412 22:41:52690884 IsRunning:1
20120412 22:41:53691069 IsRunning:1
20120412 22:41:54691236 IsRunning:0
20120412 22:41:55691428 IsRunning:0
20120412 22:41:56691614 IsRunning:0
20120412 22:41:57691810 IsRunning:0
20120412 22:41:58692001 IsRunning:0
20120412 22:41:59692193 IsRunning:0
20120412 22:42:00692364 IsRunning:0
20120412 22:42:01692542 IsRunning:0
20120412 22时42: 02692706 IsRunning: 0
20120412 22:42:03692886 IsRunning: 0
20120412 22:42:04693071 IsRunning: 0
20120412 22:42:056206204Running
: Is12062050000

采纳答案by Sam Miller

When I try to get (not set!) the current expiry time using boost expires_from_now() is seems to actually cancel the timer, yet it actually runs as expected, but does finally not call the handler.

当我尝试使用 boost expires_from_now() 获取(未设置!)当前到期时间时,似乎实际上取消了计时器,但它实际上按预期运行,但最终没有调用处理程序。

this assumption is incorrect. When you create your deadline_timer

这个假设是不正确的。当你创建你的deadline_timer

m_pTimer = new boost::asio::deadline_timer(io_service1);
m_pTimer->async_wait(handler1);

you've told it to expire immediately. Then, when you start your io_service

你已经告诉它立即过期。然后,当你开始你的io_service

m_pThread = new boost::thread(&Mytimer::runTimerThread, this);

you subsequently invoke

你随后调用

m_pTimer->expires_from_now(boost::posix_time::seconds(10));

which as the documentation describes clearly, this will cancel any outstanding handlers, emphasis added is mine

正如文档中清楚地描述的那样,这将取消任何未完成的处理程序,强调的是我的

This function sets the expiry time. Any pending asynchronous wait operations will be cancelled. The handler for each cancelled operation will be invoked with the boost::asio::error::operation_abortederror code.

此函数设置到期时间。任何挂起的异步等待操作都将被取消。将使用boost::asio::error::operation_aborted错误代码调用每个取消操作的处理程序。

To resolve this, change your Mytimer::startTimer()method as follows

要解决此问题,请Mytimer::startTimer()按如下方式更改您的方法

--- timer4.cc.orig  2012-04-13 11:18:47.000000000 -0500
+++ timer4.cc   2012-04-13 11:16:54.000000000 -0500
@@ -1,4 +1,3 @@
-
 #include <boost/asio.hpp> 
 #include <boost/thread.hpp> 
 #include <boost/date_time/posix_time/posix_time.hpp>
@@ -39,7 +38,6 @@
     m_pThread(NULL)
 {
     m_pTimer = new boost::asio::deadline_timer(io_service1); 
-    m_pTimer->async_wait(handler1); 
 }

 void Mytimer::runTimerThread()
@@ -49,8 +47,9 @@

 void Mytimer::startTimer()
 {
-    m_pThread = new boost::thread(&Mytimer::runTimerThread, this);
     m_pTimer->expires_from_now(boost::posix_time::seconds(10));
+    m_pTimer->async_wait(handler1); 
+    m_pThread = new boost::thread(&Mytimer::runTimerThread, this);
 }

 bool Mytimer::isRunning()

which results in the expected behavior

这导致了预期的行为

mbp:stackoverflow samm$ ./a.out
20120413 11:17:22922529 before timer construction
20120413 11:17:22923155 before startTimer()
20120413 11:17:22923530 IsRunning: 1
20120413 11:17:23924702 IsRunning: 1
20120413 11:17:24925971 IsRunning: 1
20120413 11:17:25927320 IsRunning: 1
20120413 11:17:26928715 IsRunning: 1
20120413 11:17:27929969 IsRunning: 1
20120413 11:17:28930601 IsRunning: 1
20120413 11:17:29931843 IsRunning: 1
20120413 11:17:30933098 IsRunning: 1
20120413 11:17:31934366 IsRunning: 0
20120413 11:17:32923594 Handler1: expired.
20120413 11:17:32934692 IsRunning: 0
20120413 11:17:33935922 IsRunning: 0
20120413 11:17:34936638 IsRunning: 0
20120413 11:17:35937905 IsRunning: 0
20120413 11:17:36939133 IsRunning: 0
20120413 11:17:37940407 IsRunning: 0
20120413 11:17:38941043 IsRunning: 0
20120413 11:17:39942319 IsRunning: 0
20120413 11:17:40942662 IsRunning: 0
20120413 11:17:41943989 IsRunning: 0
20120413 11:17:42945284 IsRunning: 0
20120413 11:17:43946555 IsRunning: 0
mbp:stackoverflow samm$ 

回答by Michael Hilbert

The following code now has the correct deadline_timer initialization, and has a private bool flag, which allows to determine, if the timer is currently running. It also has a member local handler.

下面的代码现在有正确的deadline_timer 初始化,并且有一个私有的bool 标志,它允许确定定时器当前是否正在运行。它还有一个成员本地处理程序。

class Mytimer {
public:
    Mytimer();
    void startTimer(int timeDelaySecs);
    void cancelTimer();
    void runTimerThread();
    bool isRunning();
    void timerHandler(const boost::system::error_code& ec); 
private:
    bool m_isRunning;
    boost::asio::deadline_timer* m_pTimer;
    boost::thread* m_pThread;
};

Mytimer::Mytimer()
    : m_pTimer(NULL),
      m_pThread(NULL)
{
    m_pTimer = new boost::asio::deadline_timer(io_service1); 
}

void Mytimer::runTimerThread()
{
    io_service1.run();
}

void Mytimer::startTimer(int timeDelaySecs)
{
    m_pTimer->expires_from_now(boost::posix_time::seconds(timeDelaySecs));
    m_pTimer->async_wait(boost::bind(&Mytimer::timerHandler, this, _1)); 
    m_pThread = new boost::thread(&Mytimer::runTimerThread, this);
    m_isRunning = true;
}

bool Mytimer::isRunning()
{
    return m_isRunning;
}

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