提升 Asio 异步连接竞争条件?

Boost Asio Async Connection Race Condition?

我正在查看 Boost Asio Blocking TCP Client timeout 示例,对如何实现连接超时特别感兴趣。我们如何从文档中得知回调处理程序和后续检查不会引入竞争条件?

异步连接命令

boost::asio::async_connect(socket_, iter, var(ec) = _1);

执行 var(ec) = _1 ,这是设置错误代码的处理程序。或者,可以在此处使用完整且显式的 lambda。

同时,check_deadline函数似乎是 由 deadline_ 成员调用。超时似乎是通过让截止日期强行关闭套接字来强制执行的,我们假设阻塞语句

do io_service_.run_one(); while (ec == boost::asio::error::would_block);

会return。起初我认为错误代码必须是原子的,但事实并非如此。相反,this page 似乎表明只要对 socket/context 的调用来自同一线程,链模型就会工作。

所以我们假设截止日期(在 Asio 中)的每个回调和 async_connect 例程的句柄不会同时 运行。文档中的 this 等页面暗示处理程序将仅在 run() 调用期间执行,这将阻止命令 while(ec == whatever) 在处理程序当前更改其值期间执行。

我怎么清楚地知道这一点?文档中的哪些内容明确告诉我没有处理程序会在这些例程之外执行?如果为真,proactor design pattern 上的页面必须推断出这一点,但绝不会明确指出“发起程序”指向“完成处理程序”的位置。

我发现的关闭是 documentation for io_context 说法

Synchronous operations on I/O objects implicitly run the io_context object for an individual operation. The io_context functions run(), run_one(), run_for(), run_until(), poll() or poll_one() must be called for the io_context to perform asynchronous operations on behalf of a C++ program. Notification that an asynchronous operation has completed is delivered by invocation of the associated handler. Handlers are invoked only by a thread that is currently calling any overload of run(), run_one(), run_for(), run_until(), poll() or poll_one() for the io_context.

这意味着如果我有一个线程 运行 执行 run_one() 命令,那么它的控制路径将等待直到一个处理程序可用,并最终绕过一个处理程序,然后它将 return 并检查 ec 值。

这是否正确并且是“处理程序仅由当前正在调用 运行()、run_one()、run_for()、run_until()、poll() 或 poll_one() 用于 io_context。”找到理解代码如何始终运行的最佳语句?还有其他说明吗?

Asio 库正准备标准化为 NetworkingTS。这部分确实很划算:

Handlers are invoked only by a thread that is currently calling any overload of run(), run_one(), run_for(), run_until(), poll() or poll_one() for the io_context

您得出的结论是整个示例是 100% 单线程的,这一结论是正确的¹。不能有比赛。

我个人觉得最好的资源是 Threads and Boost.Asio 页面:

  • By only calling io_context::run() from a single thread, the user's code can avoid the development complexity associated with synchronisation. For example, a library user can implement scalable servers that are single-threaded (from the user's point of view).

这也重申了之前的事实:

[...] the following guarantee:

  • Asynchronous completion handlers will only be called from threads that are currently calling io_context::run().

¹ 取决于 platform/extensions 的潜在内部服务线程除外,如 threads 页面详细信息