簡體   English   中英

什么時候必須將 io_context 傳遞給 boost::asio::spawn? (C++)

[英]When must you pass io_context to boost::asio::spawn? (C++)

我驚訝地發現下面的代碼在沒有將io_context作為第一個參數傳遞給spawn的情況下工作。 有人可以解釋為什么在這種情況下我不需要通過它,以及在什么情況下你必須明確地通過它。 我正在使用 Boost 1.75.0

#include <boost/asio/spawn.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <iostream>

int main() {

  boost::asio::io_context io_context;
  boost::asio::deadline_timer timer(io_context);

  boost::asio::spawn([&](boost::asio::yield_context yield){ // don't need to pass io_context?!
    std::cout << "started spawn" << std::endl;
    timer.expires_from_now(boost::posix_time::seconds(5));
    timer.async_wait(yield);
    std::cout << "finished spawn" << std::endl;
  });

  std::cout << "running io_context" << std::endl;
  io_context.run();
  std::cout << "finished running io_context" << std::endl;

}

Asio 增加了關聯執行器和默認執行器的概念。

關聯的執行器並不是真正新的,因為handler_invoke協議已經允許處理程序類型特定的語義。 然而,由於執行者概念的形成,它變得更加普遍。

現在您可以post任何處理程序,它將在關聯的執行程序、提供的執行程序默認執行程序上執行。 默認執行器最終是system_executor{}

所以

post([]{ puts("Hello world"); });
post(system_executor{}, []{ puts("Hello world"); });

兩個處理程序都使用system_executor

您可以將關聯的處理程序與尚未關聯的任何處理程序綁定:

post(bind_executor(ex1, []{ puts("Hello world"); }));
post(system_executor{}, bind_executor(ex1, []{ puts("Hello world"); }));

兩者都在ex1上運行處理程序,而不是后備。 結合以上內容,您已經期望這也是如此:

post(ex1, []{ puts("Hello world"); });

(這里,處理程序沒有關聯執行程序,所以ex1用作后備)

產卵

Spawn 只是一個“發布”另一種處理程序¹的包裝器。 事實上,它記錄了使用任何相關的執行程序。 該實現非常清晰地反映了這一點:

template <typename Function>
inline void spawn(BOOST_ASIO_MOVE_ARG(Function) function,
    const boost::coroutines::attributes& attributes)
{
  typedef typename decay<Function>::type function_type;

  typename associated_executor<function_type>::type ex(
      (get_associated_executor)(function));

  boost::asio::spawn(ex, BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
}

您可以看到調用get_associated_executor時沒有顯式回退,再次默認為system_executor

旁注

此外

  • spawn將在適當的地方添加一個鏈(這就是為什么在構建執行上下文時提供並發提示會產生很大不同的原因)
  • spawn可以將yield_context作為第一個參數,在這種情況下,您將有效地在同一條鏈上運行(共享執行程序)

¹ 這是一個實現細節,但通常是boost::asio::detail::spawn_helper<...> ,它再次正確傳播關聯的執行器/分配器。 我將這種類型稱為“處理程序活頁夾”

現場演示

為了說明正在使用system_executor的現實,這里有一個簡化的測試器:

編譯器資源管理器

#include <boost/asio/spawn.hpp>
#include <boost/asio/steady_timer.hpp>
#include <iostream>

int main() {
    using namespace boost::asio;
    using namespace std::chrono_literals;
    io_context ctx(1);

    spawn([](yield_context yield) {
        std::cout << "started spawn" << std::endl;

        auto ex = get_associated_executor(yield);
        //auto work = make_work_guard(ex);

        steady_timer timer(ex, 5s);
        timer.async_wait(yield);

        std::cout << "finished spawn" << std::endl;
    });

    std::cout << "running context" << std::endl;
    query(system_executor{}, execution::context).join();
    std::cout << "finished running context" << std::endl;
}

筆記:

  • ctx現在接受並發提示(如上所述)

  • ctx從未使用過 加入它不會等待 coro 完成!

  • 注意評論的work 重要的是,雖然異步操作構成工作,但Coro 本身並不工作,因此在某些情況下您可能需要保護 coro 的 scope。

  • 請注意, system_executor的加入就像你加入另一個基於線程的執行上下文一樣thread_pool

     query(system_executor{}, execution::context).join();

現在它打印

started spawn
running context
finished spawn
finished running context

與預期的5s延遲。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM