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

mag*_*ras 5 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();
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

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

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

当我想到这个问题时,我注意到计时器中对执行处理程序的一些引用,反之亦然。我知道计时器析构函数将在所有异步等待处理程序上调用取消,但这无关紧要,因为处理程序已经在执行并且无法取消。

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

我在此处此处的文档中都没有找到任何相关内容。

Tan*_*ury 4

这对于所有 I/O 对象来说都是安全且定义明确的。

\n\n
\n\n

Boost.Asio 已努力支持使用shared_ptr来延长对象(例如 a )的生命周期,通过将 a与对象steady_timer绑定到处理程序中,使其至少与异步操作序列一样长。shared_ptr文档

\n\n
\n

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

\n
\n\n

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

\n\n
    \n
  • 调用处理程序后立即
  • \n
  • io_service被摧毁了
  • \n
  • 拥有该处理程序的人io_service::service通过以下方式关闭shutdown_service()
  • \n
\n\n

异步操作文档的要求指出:

\n\n
\n

启动函数的参数将按如下方式处理:

\n\n

\xe2\x80\x94 如果参数被声明为常量引用或按值,则程序不需要在启动函数完成后保证参数的有效性。实现可以复制参数,并且所有副本将在调用处理程序后立即销毁。

\n
\n