在 Boost 1.66 上,Asio 有 deprecated asio_handler_is_continuation
钩子(Hook)函数, boost defer
的使用功能。 It seems that defer
函数的行为与 post
完全相同当 asio_handler_is_continuation==true 时。但是defer
的使用方式不同于asio_handler_is_continuation
的使用方式,而且我不确定如何正确使用 defer
.
编辑:我认为下面的示例过于冗长,无法清楚地表达我的意思。这是较短的示例:
async_read_until(stream, read_buffer, "\r\n",
[](boost::system::error_code ec, std::size_t bytes_transferred)
{
if(!ec)
async_write(stream, write_buffer, some_handler);
})
现在 async_read_until
完成后,传递的 lambda 处理程序将使用某种等同于 boost::asio::post
的方式被调用。 .但是async_write
lambda 处理程序内部是上一个异步任务的延续,所以我想使用 defer
调用 lambda 处理程序采取优化的冒险。
有什么办法可以用defer
(而不是 post
)来调用上面示例中的 lambda 处理程序?
原始帖子:我正在尝试编写一个简单的启动函数 async_echo
类似于 beast document 中的那个, 除了调用 boost::asio::async_write
的部分将被称为延续。为此,事先进行中间操作boost::asio::async_read_until
必须调用处理程序 *this
作为延续。
这是我在 beast 文档的 async_echo 示例中指的部分:
template<class AsyncStream, class Handler>
void echo_op<AsyncStream, Handler>::
operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
{
// Store a reference to our state. The address of the state won't
// change, and this solves the problem where dereferencing the
// data member is undefined after a move.
auto& p = *p_;
// Now perform the next step in the state machine
switch(ec ? 2 : p.step)
{
// initial entry
case 0:
// read up to the first newline
p.step = 1;
return boost::asio::async_read_until(p.stream, p.buffer, "\r", std::move(*this));
case 1:
// write everything back
p.step = 2;
// async_read_until could have read past the newline,
// use buffers_prefix to make sure we only send one line
return boost::asio::async_write(p.stream,
boost::beast::buffers_prefix(bytes_transferred, p.buffer.data()), std::move(*this));
case 2:
p.buffer.consume(bytes_transferred);
break;
}
// Invoke the final handler. The implementation of `handler_ptr`
// will deallocate the storage for the state before the handler
// is invoked. This is necessary to provide the
// destroy-before-invocation guarantee on handler memory
// customizations.
//
// If we wanted to pass any arguments to the handler which come
// from the `state`, they would have to be moved to the stack
// first or else undefined behavior results.
//
p_.invoke(ec);
return;
}
在 1.66 之前的日子里,我可以简单地 hook 函数如下:
template <Function, Handler>
friend bool asio_handler_is_continuation(echo_op<Function, Handler>* handler)
{
using boost::asio::asio_handler_is_continuation;
return handler.p_->step == 1 ||
asio_handler_is_continuation(std::addressof(handler.p_->handler()));
}
在 echo_op
的声明中.
从 Boost 1.66 开始,上面的代码不太可能有任何效果(没有 BOOST_ASIO_NO_DEPRECATION
宏)。所以我应该使用 defer
.
但是自boost::asio::async_read_until
有a guarantee “处理程序的调用将以等同于使用 boost::asio::io_context::post() 的方式执行。”,*this
不会使用 defer
调用, 即作为延续。
是否有任何解决方法使 boost::asio::async_read_until
使用 defer
调用处理程序?有没有利用 defer
的好例子?功能?
最佳答案
这在过去也让我感到困惑。
Executor::defer
和 Executor::post
都执行相同的操作,除了这个注释:
Note: Although the requirements placed on defer are identical to post, the use of post conveys a preference that the caller does not block the first step of f1's progress, whereas defer conveys a preference that the caller does block the first step of f1. One use of defer is to convey the intention of the caller that f1 is a continuation of the current call context. The executor may use this information to optimize or otherwise adjust the way in which f1 is invoked. —end note
https://www.boost.org/doc/libs/1_67_0/doc/html/boost_asio/reference/Executor1.html
因此,链接延续的责任似乎已成为 Executor
模型的实现细节。
据我所知,这意味着您需要做的就是调用自由函数 defer(executor, handler)
,执行程序将“做正确的事”
更新:
找到一些说明如何通过最终执行程序链接处理程序的文档:
文档来源:https://github.com/chriskohlhoff/asio-tr2/blob/master/doc/executors.qbk
示例:https://github.com/chriskohlhoff/executors/blob/v0.2-branch/src/examples/executor/async_op_2.cpp
请参阅 async_op_2.cpp 中的第 38+ 行
关于c++ - 如何在组合函数中使用 boost::asio::defer()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50176602/