boost::asio::yield_context如何工作?

问题描述 投票:0回答:1

我正在阅读

boost::asio
的文档并遇到了这个示例:

void foo(boost::asio::yield_context yield)
{
  size_t n = socket.async_read_some(buffer, yield);

  // ...
}

我很困惑:

  1. 如果我正确理解 asyncio,则对
    async_read_some
    的调用不会阻塞。
  2. 这意味着此调用将注册函数的其余部分以在数据实际准备好读取时运行。

我看到

boost::asio
如何实现这个的两个选项:

  1. 当调用
    socket.async_read_some
    时,该函数本身会调用事件循环中的一个函数,该函数尝试查找任何准备好处理的事件并尝试调用这些回调。
  2. 一些
    setjmp
    /
    longjmp
    魔法为此函数注册了一个回调,并在稍后返回。

这两个选项似乎都不起作用:

  1. 调用堆栈看起来像这样:
...
boost_internal_magic
async_read_some
foo
...
main

因为我们还没有从 foo 返回。但是,如果使用

yield_context
调用所有函数,我不知道我们如何实际注册回调,因为没有代码点可以作为函数调用跳转到。

  1. 只有 1 个堆栈,但
    asyncio
    的全部要点是在同一线程上运行多个并发“代理”或“协程”或其他东西。每个代理都需要自己的堆栈,所以这似乎也不起作用。

boost::asio::yield_context
如何将函数变成可以注册的回调?具有相同功能的最小无依赖 C++ 代码是什么样的?

c++ asynchronous boost implementation asio
1个回答
0
投票

诀窍在于

yield_context
采用了堆栈协程。协程有自己独立的堆栈,该堆栈在挂起/恢复周期中保留。

其技术实现是在 Boost Context 中。早期版本的 Asio 实际上是在另一个库之上实现的:Boost Coroutine(在底层使用 Boost Context)。

Asio 1.24.0 / Boost 1.80 更改以跳过中间人:

当面向 C++11 及更高版本时,这些函数直接通过 Boost.Context 实现。现有的重载已保留但已弃用。

进一步阅读

您可以在该库的文档中阅读 Boost Context 的技术工作原理:https://www.boost.org/doc/libs/1_86_0/libs/context/doc/html/index.html

要详细了解实施的细节,您可以跟踪实施的进展,例如在:

住在Coliru

#define BOOST_ASIO_DISABLE_BOOST_COROUTINE 1
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

namespace asio = boost::asio;
using namespace std::chrono_literals;

int main() {
    asio::io_context ctx;

    spawn(
        ctx,
        [](asio::yield_context yield) {
            asio::steady_timer tim(yield.get_executor(), 3s);
            tim.async_wait(yield);
        },
        asio::detached);

    ctx.run();
}

这将引导您到

boost/asio/impl/spawn.hpp
,并向您展示非 Boost.Coroutine 实现实际上使用了 Boost.Context 的 Fiber (
BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER
)。

// Spawned thread implementation using Boost.Context's fiber.
class spawned_fiber_thread : public spawned_thread_base
{
public:
  typedef boost::context::fiber fiber_type;

  spawned_fiber_thread(fiber_type&& caller)
    : caller_(static_cast<fiber_type&&>(caller)),
      on_suspend_fn_(0),
      on_suspend_arg_(0)
  {
  }

// ...

从这里您可以任意深入地了解实现细节。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.