当I/O对象已经有Executor时,为什么需要`net::Dispatch`?
我正在从本例中学习Boost.Beast&;Boost.Asiolibs/beast/example/http/server/async-ssl/http_server_async_ssl.cpp - 1.77.0。
据我所知,发生在I/O对象上的所有I/O操作都发生在该对象的I/O执行上下文中。异步操作将与I/O上下文的run
位于同一线程中,因为它们都由I/O上下文的run
(间接)调用。
在本例中(请参见上面的链接),当连接建立时,接受者为新连接分配一条专用链:
do_accept()
{
// The new connection gets its own strand
acceptor_.async_accept(
net::make_strand(ioc_),
beast::bind_front_handler(
&listener::on_accept,
shared_from_this()));
}
这是否意味着在新连接上发生的所有I/O操作都发生在链上?如果是,为什么该示例在要调用async_read
时使用net::dispatch
再次指定链?
// Start the asynchronous operation
void
run()
{
// We need to be executing within a strand to perform async operations
// on the I/O objects in this session. Although not strictly necessary
// for single-threaded contexts, this example code is written to be
// thread-safe by default.
net::dispatch(
stream_.get_executor(),
beast::bind_front_handler(
&session::on_run,
shared_from_this()));
}
如果我们直接调用async_read
而不经过net::dispatch
,有什么区别?谢谢。:)
解决方案
这是否意味着在新连接上发生的所有I/O操作都发生在链上?
这意味着接受的套接字将获得引用该链的Executor的副本。这确实意味着从该服务对象启动的所有异步操作在默认情况下(!)将在该链上调用它们的完成处理程序。但是,这不适用于任何其他操作,如启动函数(例如s.async_read_some
)本身。
因此,为了确保所有操作都发生在链上,您必须确保所有启动都发生在同一链上。在许多情况下,这将是自动的,因为许多启动发生在前一个操作的完成中-因此已经在链上-但不是第一个操作,如您所见。
(可以说,在新链的开始处,因此当刚刚创建IO对象并且该链是该IO对象的私有时,可以从任何线程安全地进行第一次发起,逻辑上成为链中的一部分。你可以把它看作是链本身的分叉点(诞生)。这是因为没有正在运行的操作,也没有其他线程可能持有对它的引用。)相关文章