从其处理程序或处理程序dtor中销毁boost :: asio计时器是否安全?

时间:2016-02-19 14:43:45

标签: c++ boost boost-asio

在我们的产品中,我们的代码可以简化为基本功能:

#include <boost/asio/steady_timer.hpp>
#include <functional>

void DelayedCall(
    boost::asio::io_service& io,
    boost::asio::steady_timer::duration delay,
    std::function<void()> f)
{
    auto timer = std::make_shared<boost::asio::steady_timer>(io, delay);
    timer->async_wait(
        [timer, f](boost::system::error_code const&)
        {
            // Probably it's ok to do even this:
            //timer.reset();
            f();
        }
    );
}

为简单起见,假设io对象具有全局生命周期。

正如您所见,计时器对象将在处理程序的析构函数中被销毁。

当我想到这个问题时,我要小心定时器中的一些引用执行处理程序,反之亦然。我知道timer析构函数会在所有异步等待处理程序上调用cancel,但这与处理程序已经执行并且无法取消无关。

现在我认为,当时间到来时,计时器对象只是post() io_service的处理程序,因此计时器和处理程序彼此独立。尽管如此,快速尝试调查asio源代码失败了,所以我仍然不确定我们的代码是否正确。

我在文档中找不到任何与herehere相关的内容。

2 个答案:

答案 0 :(得分:2)

这对所有I / O对象都是安全且定义良好的。

Boost.Asio已经努力支持使用shared_ptr来延长对象(例如steady_timer)的生命周期,使其至少与通过绑定{的一系列异步操作一样长。 {1}}将对象转换为处理程序。 documentation注释:

  

[...]允许程序使用shared_ptr简化其资源管理。如果对象的生命周期与连接的生命周期(或某些其他异步操作序列)相关联,则对象的shared_ptr<>将绑定到与其关联的所有异步操作的处理程序中。 / p>

为了支持这一点,启动函数按值接受处理程序,Boost.Asio负责维护处理程序的有效性。实现可以制作处理程序的副本,并保证所有副本都被销毁:

  • 在调用处理程序之后立即
  • shared_ptr被销毁
  • 拥有处理程序的io_service通过shutdown_service()
  • 关闭

requirements on asynchronous operations documentation州:

  

启动功能的参数将被视为如下:

     

- 如果参数声明为const引用或by-value,则在启动函数完成后,程序不需要保证参数的有效性。实现可以创建参数的副本,并且所有副本将在不迟于调用处理程序之后立即销毁。

答案 1 :(得分:0)

<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAG"/> 引用计数器变为0时,计时器将被销毁,并且当shared_ptr所属的关闭将被销毁时,将发生这种情况。因此以这种特殊方式使用它是安全的。但请注意,如果您更改将计时器传递给lambda的方式,例如通过引用shared_ptr或移动[&timer],则此代码将崩溃,因为复制时没有[timer = std::(move(timer))]引用递增计时器将在你的处理程序范围出口处销毁。