asio/strand:为什么计时器的行为不同
asio/strand: why is behaviour with timer different?
我一直在学习这篇优秀的asio教程,但对链的确切作用感到困惑。我的理解是,它们就像一组处理程序(回调)的队列一样工作,这样队列中的处理程序就会按顺序执行。但一些实验表明我错了。有人能解释一下它们到底是什么吗?
我从示例6c开始,它在触发计时器之前执行PrintNum(1)
到PrintNum(5)
,每个都有1秒的延迟。(毫无疑问,如果我在启动计时器后将PrintNum调用移动到,也会发生这种情况!然后我意识到调用TimerHandler的请求在计时器触发之前不会进入串队列。)
我的第一个变体是只删除计时器上的链引用,但将它们保留在PrintNum上(请参阅要点上的完整代码):
strand->post( boost::bind( &PrintNum, 1 ) );
strand->post( boost::bind( &PrintNum, 2 ) );
strand->post( boost::bind( &PrintNum, 3 ) );
strand->post( boost::bind( &PrintNum, 4 ) );
strand->post( boost::bind( &PrintNum, 5 ) );
boost::shared_ptr< boost::asio::deadline_timer > timer(
new boost::asio::deadline_timer( *io_service )
);
timer->expires_from_now( boost::posix_time::seconds( 1 ) );
timer->async_wait( boost::bind( &TimerHandler, _1, timer ) );
现在,计时器独立于PrintNum调用运行。我得到了我期望的结果。
我的问题出现在我的第二个变体(见要点)中,我删除了对PrintNum的串调用,但将它们保留在计时器上:
io_service->post( boost::bind( &PrintNum, 1 ) );
io_service->post( boost::bind( &PrintNum, 2 ) );
io_service->post( boost::bind( &PrintNum, 3 ) );
io_service->post( boost::bind( &PrintNum, 4 ) );
io_service->post( boost::bind( &PrintNum, 5 ) );
boost::shared_ptr< boost::asio::deadline_timer > timer(
new boost::asio::deadline_timer( *io_service )
);
timer->expires_from_now( boost::posix_time::milliseconds( 1000 ) );
timer->async_wait(
strand->wrap( boost::bind( &TimerHandler, _1, timer, strand ) )
);
(你会在要点代码中看到,我把它打乱了一点,但行为基本上是一样的。)
我在这里所期望的是,strand基本上什么都不做:我一次在strand队列中只有一个处理程序(TimerHandler)。因此,我期望计时器独立于PrintNum调用而滴答作响。但我看到的是,PrintNum调用仍然具有优先级:在TimerHandler被允许执行之前,所有5个调用都必须完成。
(值得指出的是,Drew Benton教程中的示例6c完全是为了确保TimerHandler和PrintNum都不会同时运行。我的变体故意取消了这种保证;我的出发点是想了解示例6c是解决问题的方法。)
我想我现在可以自己回答了。在第二个例子中,问题与strand的使用无关;如果去除CCD_ 3,则行为(有点)相同。问题是线程都很忙将线程池中的线程数增加到6,我们就会得到预期的行为:计时器在创建后1秒触发。当有5个或更少的线程时,TimerHandler
将不会被调用,直到第一个PrintNum
调用完成。
理解这个例子的另一件重要的事情,正如我在问题中已经指出的,是strand->wrap()
被计时器触发,而不是TimerHandler
。当计时器关闭时,TimerHandler
将被添加到队列中。但是所有的PrintNum
请求都已经被调用了,所有的线程都很忙!
我创建了另一个要点,它将TimerHandler
放在自己的io_service中,并带有自己的专用线程。
boost::shared_ptr< boost::asio::io_service > io_service2(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work2(
new boost::asio::io_service::work( *io_service2 )
);
boost::shared_ptr< boost::asio::io_service::strand > strand2(
new boost::asio::io_service::strand( *io_service2 )
);
...
boost::thread_group worker_threads;
for( int x = 0; x < 2; ++x )
{
worker_threads.create_thread( boost::bind( &WorkerThread, x==0? io_service2 : io_service ) );
}
...
boost::shared_ptr< boost::asio::deadline_timer > timer(
new boost::asio::deadline_timer( *io_service2 )
);
timer->expires_from_now( boost::posix_time::milliseconds( 1000 ) );
timer->async_wait(
strand2->wrap( boost::bind( &TimerHandler, _1, timer, strand2 ) )
);
现在,无论PrintNum
调用占用了多少线程,计时器都将可靠地运行。(为了强调这一点,我只为所有PrintNum调用提供一个线程来共享,迫使它们串行运行。)
- Linux的Cpp上的计时器
- 提升 ASIO 无法识别计时器对象
- 提升 asio 并发计时器取消问题与链
- 使用单体计时器的pthread_cond_timedwait有时会比预期晚超时
- 窗口中的微秒计时器
- 计时器是否从另一个线程启动?
- 如何在 c++ 中创建计时器
- C++回调计时器实现
- 在计时器或主线程外部的命令上销毁/替换线程
- 如何制作每秒从 30 乘 1 倒计时的计时器?
- 保留计时器集合(对象与指针)的最佳方法
- 在网络套接字计时器滴答后增加asio短读错误
- 是否可以仅使用标准 c++/c++11 实现不带"sleep"的计时器?
- 在没有NtSetTimerResolution的Windows上提高计时器分辨率(高分辨率)
- 计时器坏了或者其他什么的
- 功能计时器阻止主功能继续
- IO服务重新启动后,Boost最后期限计时器持续触发
- boost asio计时器是否会在"取消"时阻塞
- Poco 计时器,具有来自同一类的回调
- asio/strand:为什么计时器的行为不同