【发布时间】:2018-05-04 13:53:17
【问题描述】:
在 Boost 1.66 上,Asio 具有 deprecated 和 asio_handler_is_continuation 挂钩函数,促进了 defer 函数的使用。当 asio_handler_is_continuation==true 时,It seems thatdefer 函数的行为与 post 完全相同。但是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 等效的方式调用。但是 lambda 处理程序中的 async_write 是上一个异步任务的延续,所以我想使用 defer 调用 lambda 处理程序以利用优化。
有没有办法使用defer(而不是post)来调用上面示例中的lambda处理程序?
ORIGINAL POST:我正在尝试编写一个简单的启动函数async_echo,类似于beast document 中的那个,除了调用boost::asio::async_write 的部分将被称为延续。为此,之前的中间操作boost::asio::async_read_until 必须调用处理程序*this 作为延续。
这是我在野兽文档的 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 之前的日子里,我可以简单地挂钩函数如下:
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函数的好例子?
【问题讨论】:
-
我也想知道这个问题的答案。而你的问题恰恰反映了我对此事的看法。
asio_handler_is_continuation的语义不同于post与defer的使用。 -
@VinnieFalco 在这种情况下我们必须使用
asio_handler_is_continuation。看我的回答。
标签: c++ boost boost-asio boost-beast