ASIO:它是否为 运行 不同线程中的完成处理程序定义了行为?
ASIO: Is it defined behavior to run a completion handler in a different thread?
在以下示例中,计时器与 io_context 执行程序相关联。但是随后,处理程序被告知在线程池中执行。原因是,因为处理程序实际上执行阻塞代码,而我不想阻塞 io_context.
的 run
函数
但是文档states
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.
如代码所示,处理程序由 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();
}
running in tp: 1
running in ioc: 0
要事第一。
您可以在任何地方 运行 处理程序。它是否会导致 UB 取决于您在处理程序中执行的操作。
我会将您的问题解释为询问“观察到的行为是否与记录的 requirements/guarantees 处理程序调用相矛盾?”
这是否与文档相矛盾?
没有。
您有两个不同的执行上下文。其中之一是 io_context
(您链接到其文档),另一个是 thread_pool
.
您已要求在 tp
上调用处理程序(通过将处理程序绑定到其执行程序)。
因此,deadline_timer
在构造时绑定到的默认执行程序被处理程序的 关联执行程序 否决。
您在查看不适用此案例的 io_context
文档时感到困惑:deadline-timer 的完成永远不会发布到 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();
}
打印例如
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
注意
- 绑定的执行者总是占上风
- 有系统执行器的回退 (see its effect)
有关 post
的语义,请参阅 the docs or e.g.
在以下示例中,计时器与 io_context 执行程序相关联。但是随后,处理程序被告知在线程池中执行。原因是,因为处理程序实际上执行阻塞代码,而我不想阻塞 io_context.
的run
函数
但是文档states
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.
如代码所示,处理程序由 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();
}
running in tp: 1 running in ioc: 0
要事第一。
您可以在任何地方 运行 处理程序。它是否会导致 UB 取决于您在处理程序中执行的操作。
我会将您的问题解释为询问“观察到的行为是否与记录的 requirements/guarantees 处理程序调用相矛盾?”
这是否与文档相矛盾?
没有。
您有两个不同的执行上下文。其中之一是 io_context
(您链接到其文档),另一个是 thread_pool
.
您已要求在 tp
上调用处理程序(通过将处理程序绑定到其执行程序)。
因此,deadline_timer
在构造时绑定到的默认执行程序被处理程序的 关联执行程序 否决。
您在查看不适用此案例的 io_context
文档时感到困惑:deadline-timer 的完成永远不会发布到 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();
}
打印例如
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
注意
- 绑定的执行者总是占上风
- 有系统执行器的回退 (see its effect)
有关 post
的语义,请参阅 the docs or e.g.