提升 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 页面详细信息
我正在查看 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 页面详细信息