ASIO:是否定义了在不同线程中运行完成处理程序的行为?

Joh*_*itb 6 c++ boost asynchronous boost-asio c++20

在以下示例中,计时器与 io_context 执行器关联。但随后,处理程序被告知在线程池中执行。原因是,因为处理程序实际上执行的是阻塞代码,而我不想阻塞runio_context的函数。

但文档指出

处理程序仅由当前正在为 io_context 调用 run()、run_one()、run_for()、run_until()、poll() 或 poll_one() 的任何重载的线程调用。

如代码所示,处理程序由 thread_pool 在run. 这种行为定义明确吗?它也适用于套接字吗?

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

int main() {
    using namespace boost::asio;
    thread_pool tp(4);

    io_context ioc;
    deadline_timer dt(ioc, boost::posix_time::milliseconds(500));
    dt.async_wait(bind_executor(tp, [&](boost::system::error_code){
        std::cout << "running in tp: " << tp.get_executor().running_in_this_thread() << std::endl;
        std::cout << "running in ioc: " << ioc.get_executor().running_in_this_thread() << std::endl;
        exit(0);
    }));

    auto wg = make_work_guard(ioc);
    ioc.run(); 
}
Run Code Online (Sandbox Code Playgroud)
running in tp: 1
running in ioc: 0
Run Code Online (Sandbox Code Playgroud)

神箭链接

seh*_*ehe 1

首先要事。

您可以在任何您想要的地方运行处理程序。是否导致UB取决于您在处理程序中执行的操作。

我将您的问题解释为询问“观察到的行为是否与处理程序调用的记录要求/保证相矛盾?”

这与文档相矛盾吗?

它不是。

您有两个不同的执行上下文。其中之一是io_context(您链接到其文档),另一个是thread_pool.

您要求调用处理程序tp(通过将处理程序绑定到其执行程序)。

deadline_timer因此,构造时绑定的默认执行程序将被处理程序的关联执行程序否决。

通过查看不管辖这种情况的文档,您会感到困惑io_context:截止日期计时器的完成从未发布到io_context. thread_pool根据您的具体要求,它会发布到 的上下文中。

正如预期的那样,处理程序在运行执行上下文的tp线程上调用。

简化与细化

这是一个直接使用的简化示例post,而不是通过任意异步启动函数来执行此操作。

此外,它还执行目标执行器和关联执行器(如果有)的所有组合。

住在科里鲁

#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;

int main() {
    std::cout << std::boolalpha << std::left;

    asio::io_context ioc;
    asio::thread_pool tp(4);

    auto xioc = ioc.get_executor();
    auto xtp  = tp.get_executor();

    static std::mutex mx; // prevent jumbled output

    auto report = [=](char const* id, auto expected) {
        std::lock_guard lk(mx);

        std::cout << std::setw(11) << id << " running in tp/ioc? "
                  << xtp.running_in_this_thread() << '/'
                  << xioc.running_in_this_thread() << " "
                  << (expected.running_in_this_thread() ? "Ok" : "INCORRECT")
                  << std::endl;
    };

    asio::post(tp,  [=] { report("direct tp", xtp); });
    asio::post(ioc, [=] { report("direct ioc", xioc); });

    asio::post(ioc, bind_executor (tp,  [=] { report("bound tp.A", xtp); }));
    asio::post(tp,  bind_executor (tp,  [=] { report("bound tp.B", xtp); }));
    asio::post(     bind_executor (tp,  [=] { report("bound tp.C", xtp); }));

    asio::post(ioc, bind_executor (ioc, [=] { report("bound ioc.A", xioc); }));
    asio::post(tp,  bind_executor (ioc, [=] { report("bound ioc.B", xioc); }));
    asio::post(     bind_executor (ioc, [=] { report("bound ioc.C", xioc); }));

    // system_executor doesn't have .running_in_this_thread()
    // asio::post([=] { report("system", asio::system_executor{}); });

    ioc.run();
    tp.join();
}
Run Code Online (Sandbox Code Playgroud)

打印例如

direct tp   running in tp/ioc? true/false Ok
direct ioc  running in tp/ioc? false/true Ok
bound tp.C  running in tp/ioc? true/false Ok
bound tp.B  running in tp/ioc? true/false Ok
bound tp.A  running in tp/ioc? true/false Ok
bound ioc.C running in tp/ioc? false/true Ok
bound ioc.B running in tp/ioc? false/true Ok
bound ioc.A running in tp/ioc? false/true Ok
Run Code Online (Sandbox Code Playgroud)

注意

  • 受约束的执行者始终占上风
  • 有一个系统执行器的回退(查看其效果

有关语义,请post参阅文档或例如何时必须将 io_context 传递给 boost::asio::spawn?(C++)