【问题标题】:Why is `net::dispatch` needed when the I/O object already has an executor?当 I/O 对象已经有执行器时,为什么需要 `net::dispatch`?
【发布时间】:2021-10-17 03:43:19
【问题描述】:

我正在从这个例子中学习 Boost.Beast 和 Boost.Asio libs/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有什么区别?谢谢。 :)

【问题讨论】:

    标签: c++ boost-asio boost-beast


    【解决方案1】:

    这是否意味着在新连接上发生的所有 I/O 操作都发生在链中?

    这意味着接受的套接字获得了引用链的执行程序的副本。这确实意味着从该服务对象启动的所有异步操作将默认情况下 (!) 在该链上调用它们的完成处理程序。但是,这不适用于任何其他操作,例如启动函数(例如s.async_read_some)本身。

    因此,要确保所有操作都发生在链上,您必须确保任何启动都发生在同一链上。在许多情况下,这将是自动的,因为许多启动发生在前一个操作的完成中 - 因此已经在链上 - 但不是第一个,如您所见。

    (可以说,在一个新链的开头,所以当一个 IO 对象刚刚创建并且该链是该 IO 对象的私有时,第一次启动可以从任何线程安全地进行,逻辑上变为链中的一部分。您可以将其视为链本身的分叉点(“诞生”)。这是因为没有任何操作可以进行,也没有其他线程可能持有对它的引用。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多