如何在组合函数中使用 boost::asio::defer()?

he *_*led 4 c++ boost boost-asio boost-beast

在 Boost 1.66 中,Asio弃用asio_handler_is_continuation钩子函数,促进了defer函数的使用。 defer函数的行为似乎postasio_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);
    })
Run Code Online (Sandbox Code Playgroud)

现在async_read_until完成后,传递的 lambda 处理程序将使用某种等效于boost::asio::post. 但是async_write在 lambda 处理程序内部是上次异步任务的延续,所以我想调用 lambda 处理程序来利用defer优化。

有没有办法使用defer(而不是post)来调用上面示例中的 lambda 处理程序?

ORIGINAL POST:我正在尝试编写一个async_echo类似于野兽文档中的简单启动函数,除了调用的部分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;
}
Run Code Online (Sandbox Code Playgroud)

在 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()));
}
Run Code Online (Sandbox Code Playgroud)

的声明内echo_op

从Boost 1.66开始,上面的代码不太可能有任何效果(没有BOOST_ASIO_NO_DEPRECATION宏)。所以我应该使用defer.

但是,由于boost::asio::async_read_until保证说:“处理程序的调用将被以某种方式等效进行使用boost ::支持ASIO :: io_context ::后()”,*this将不使用被调用defer,也就是说,作为一个延续。

是否有任何解决方法可以boost::asio::async_read_until使用调用处理程序defer?有没有利用defer函数的好例子?

Ric*_*ges 5

这在过去也让我感到困惑。

Executor::defer并且Executor::post都执行相同的操作,除了这个注意事项:

注意:虽然对 defer 的要求与 post 相同,但 post 的使用传达了调用者不会阻止 f1 进程的第一步的偏好,而 defer 传达的偏好是调用者确实阻止了 f1 的第一步。defer 的一种用途是传达调用者的意图,即 f1 是当前调用上下文的延续。执行器可以使用此信息来优化或以其他方式调整调用 f1 的方式。——尾注

https://www.boost.org/doc/libs/1_67_0/doc/html/boost_asio/reference/Executor1.html

因此,链接延续的责任似乎已成为Executor模型的实现细节。

据我所知,这意味着您需要做的就是调用 free 函数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 行以上

  • @herambled 这是这里描述的方法:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4242.html#executors.on_the_need_for_dispatch__post_and_defer (2认同)