C++20,boost协程

协程(Coroutines)详解

1. 协程的基本概念

  • 暂停和恢复: 协程可以在某个点暂停执行,并在稍后从暂停的地方继续执行。这与传统的函数调用不同,传统函数一旦开始执行就会一直运行到结束。
  • 异步编程: 协程非常适合处理异步操作,比如网络请求、文件I/O等。它们可以在等待I/O操作完成时暂停,从而避免阻塞线程。
  • 轻量级: 协程比线程更轻量级,因为它们不需要操作系统的线程管理,切换上下文的开销也更小。

2. 协程的执行流程

  • 启动协程 : 使用 co_spawn 启动协程,并将其提交给执行器。
  • 遇到 co_await : 协程在 co_await 处暂停执行,将控制权交还给执行器。
  • 异步操作继续进行: 异步操作在后台继续进行,不会阻塞线程。执行器可以调度其他任务或协程。
  • 恢复执行: 当异步操作完成时,执行器将控制权交还给协程,协程从暂停的地方继续执行。

3. 关键概念和术语

co_await
  • 作用: 用于在协程中等待一个异步操作完成。它会暂停协程的执行,直到被等待的操作完成,然后恢复执行。
awaitable
  • 定义 : 表示可以被 co_await 等待的对象,封装了异步操作的状态和结果。
  • 作用 : 与 co_await 一起使用,协程会在 co_await 处暂停,直到 awaitable 对象表示的异步操作完成。
co_spawn
  • 作用: 启动一个新的协程。接受一个执行器(executor)、一个协程函数和一个分离策略(detached),并启动协程的执行。
执行器(executor)
  • 定义 : 用于管理协程执行的对象。它负责调度协程的执行。在 Boost.Asio 中,io_context 就是一个执行器。
use_awaitable
  • 作用 : 一个标记,用于指示异步操作应该返回一个 awaitable 对象,从而可以在协程中使用 co_await 来等待这些操作的完成。

4. 示例代码解析

echo 协程
cpp 复制代码
awaitable<void> echo(ip::tcp::socket socket)
{
    try
    {
        char data[1024];
        for (;;)
        {
            std::size_t n = co_await socket.async_read_some(buffer(data), use_awaitable);
            co_await async_write(socket, buffer(data, n), use_awaitable);
        }
    }
    catch (const std::exception& e)
    {
        std::cout << "Exception is " << e.what() << std::endl;
    }
}
  • 功能: 实现一个简单的回显服务器,接收客户端发送的数据并将其原样返回。
  • 流程 : 使用 co_await 等待异步读取和写入操作,通过无限循环持续处理客户端的数据,捕获并打印任何异常。
listener 协程
cpp 复制代码
awaitable<void> listener()
{
    auto executor = co_await this_coro::executor;
    ip::tcp::acceptor acceptor(executor, { ip::tcp::v4(), 10086 });
    for (;;)
    {
        ip::tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
        co_spawn(executor, echo(std::move(socket)), detached);
    }
}
  • 功能: 负责监听端口并接受新的TCP连接。
  • 流程 : 获取当前协程的执行器,创建TCP接受器,使用 co_await 等待异步接受连接,每当接受到一个新的连接时,使用 co_spawn 启动一个新的 echo 协程来处理该连接。
main 函数
cpp 复制代码
int main()
{
    try
    {
        io_context io_context(1);
        signal_set signals(io_context, SIGINT, SIGTERM);
        signals.async_wait(& 
            {
                io_context.stop();
            }
        );
        co_spawn(io_context, listener(), detached);
        io_context.run();
    }
    catch (const std::exception& e)
    {
        std::cout << "Exception is " << e.what() << std::endl;
    }
}
  • 功能: 程序的入口点,负责初始化I/O上下文并启动监听协程。
  • 流程 : 创建 io_context 对象,设置信号处理器,捕捉 SIGINTSIGTERM 信号,并在接收到信号时停止 io_context,使用 co_spawn 启动 listener 协程,调用 io_context.run() 开始事件循环,处理异步操作。

5. 协程与线程的对比

  • 协程: 轻量级、用户态、非抢占式,适用于I/O密集型任务。
  • 线程: 重量级、内核态、抢占式,适用于CPU密集型任务。

6. 常见问题解答

  • 为什么在 co_spawn 中传递 coroutine() 而不是 coroutine : 传递 coroutine() 是因为 co_spawn 需要一个 awaitable 对象,而不是一个可调用对象。coroutine() 调用协程函数并返回一个 awaitable 对象。
相关推荐
AskHarries20 小时前
权限模型:Shell、Browser、文件读写的安全边界
服务器·前端·网络
咖啡星人k20 小时前
MonkeyCode 网络架构:WebSocket、SSE与实时协作的技术选型
网络·websocket·架构·monkeycode
团象科技20 小时前
外贸站选海外服务器 拆解跨境运营中常被忽略的核心性能细节
运维·服务器
AI帮小忙21 小时前
主机安全排查
linux·服务器·安全
稷下元歌21 小时前
七天学会plc 加机器视觉完整笔记:S7-1200 数据类型、存储区与寻址方式(I/Q/M/DB 详解)。
网络·数据库·笔记
liulilittle21 小时前
bpftrace 跟踪 tcp_write_xmit (内核TCP写出提交)
网络·网络协议·tcp/ip
星光不负赶路人!21 小时前
【问题解决】xftp工具无法连接Windows问题解决
网络
程序员老舅21 小时前
从内核视角,看Linux文件读写过程
linux·服务器·c++·内核·linux内核·vfs·linux内存
李少兄1 天前
Linux服务器IP地址查询
linux·服务器·tcp/ip
liulilittle1 天前
TCP KCC v1.0(卡尔曼拥塞控制)
linux·服务器·网络·tcp/ip·计算机网络·tcp·通信