假设一个线程正在运行 asio 事件循环,我如何推迟在该线程中调用 lambda?
#include <thread>
#include <iostream>
#include <asio.hpp>
int main()
{
asio::io_context io_context;
// hook something into io_context
std::jthread t([&]{io_context.run();});
// now how to let eventoop thread call lambda
io_context.async_call([]{std::cout<<"Hello World!";}); // this method does not exist
}
我正在寻找本着http://docs.libuv.org/en/v1.x/async.html#c.uv_async_t精神的功能,在libuv中,通过
uv_async_send
这些保证是可能的:
异步句柄允许用户“唤醒”事件循环并获取 从另一个线程调用的回调。
从任何线程调用此函数都是安全的。回调将是 调用循环线程。
uv_async_send() 是异步信号安全的。调用这个函数是安全的 来自信号处理程序。
asio 中的等价物是什么?
在 Asio 中,您将[1] 工作发布给执行者。
执行器与执行上下文相关联。在您的示例中,
io_context
就是这样一个执行上下文。
所以,你会说:
asio::post(io_context.get_executor(), []{std::cout<<"Hello World!";});
ADL 使得您可以使用不合格的:
post(io_context.get_executor(), []{std::cout<<"Hello World!";});
接下来,为了方便起见,Asio 支持发布“到”执行上下文,在这种情况下,将使用其默认执行器:
post(io_context, []{std::cout<<"Hello World!";});
如果您使用
asio::dispatch
发布的处理程序可能会在调用线程上调用iff执行器与该线程匹配。例如。在给定的示例中 asio::dispatch
的行为就像
asio::post
除非您从已经在“服务线程”(运行 io 上下文的线程)上运行的处理程序内部使用它。相关执行者
strand<>
执行器确保只有一个处理程序同时运行,使您能够获得类似于同步代码中的互斥的访问序列化。按理说,执行者的选择对于该机制的正确性至关重要。该库具有“关联执行器”功能,使其能够在通用代码中正确满足执行器要求。
例如,组合操作(如
asio::async_read_until
)将正确使用关联的执行器,即使对于它内部发布的任何中间处理程序也是如此。要关联执行者,请使用
bind_executor
,例如:
asio::thread_pool tp; // multi threading execution context
auto strand = make_strand(tp.get_executor()); // using a strand to serialize handlers
auto handler = [] { std::cout << “On the strand: “ << strand.running_in_this_thread(); };
auto bound = bind_executor(strand, handler);
// Now even posting _without_ an executor will invoke the bound handler on the intended executor:
asio::post(bound);
更多相关信息请参阅:
[1]
asio::post
、
asio::defer
、
asio::dispatch