代码:
在主题1中:
boost::async_read(socket, buffer, strand.wrap(read_handler));
在主题2中:
strand.post([](){socket.async_write_some(buffer, strand.wrap(write_handler))});
很明显, read_handler , async_write_some , write_handler 受到strand的保护,它们不会并发。但是,async_read是一个组合操作,它将对async_read_some调用零次或多次,那些async_read_some也需要通过strand保护,否则它们可能与线程2中的async_write_some并发。
但是从代码中,strand只包装了 read_handler ,asio如何使所有中间操作(async_read_some)也被链包裹?
答案 0 :(得分:3)
简而言之,asio_handler_invoke
使得人们可以在不同处理程序的上下文中自定义处理程序的调用。在这种情况下,从strand.wrap()
返回的对象具有与之关联的自定义asio_handler_invoke
策略,该策略将处理程序分配到包装初始处理程序的链中。从概念上讲,它如下:
template <typename Handler>
struct strand_handler
{
void operator()();
Handler handler_;
boost::asio::strand dispatcher_;
};
// Customize invocation of Function within context of custom_handler.
template <typename Function>
void asio_handler_invoke(Function function, strand_handler* context)
{
context->dispatcher_.dispatch(function);
}
strand_handler wrapped_completion_handler = strand.wrap(completion_handler);
using boost::asio::asio_handler_invoke;
asio_handler_invoke(intermediate_handler, &wrapped_completion_handler);
自定义asio_handler_invoke
挂钩位于argument-dependent lookup。详细信息记录在Handler requirement:
使函数对象
f
像执行f()
一样执行。使用与参数相关的查找来定位
asio_handler_invoke()
函数。如果没有用户提供的功能,则函数boost::asio::asio_handler_invoke()
将作为默认值。
有关asio_handler_invoke
的详细信息,请考虑阅读this answer。
请注意,可以在启动功能中尝试操作。该文档特定于中间处理程序将在与最终完成处理程序相同的上下文中调用。因此,给出:
assert(strand.running_in_this_thread());
boost::async_read(socket, buffer, strand.wrap(read_handler));
boost::async_read
本身必须在strand
的上下文中调用才能是线程安全的。有关线程安全和线索的详细信息,请参阅this答案。