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 对象。
相关推荐
威联通网络存储6 小时前
某大型制造企业基于威联通 NAS 的海量数据存储与容灾归档实践
网络·nas
xdscode7 小时前
Linux云服务器安装openclaw,并对接飞书通道
linux·服务器·飞书·openclaw
lswzw7 小时前
win11家庭版 安装 openclaw
服务器
LegendNoTitle8 小时前
计算机三级等级考试 网络技术 选择题考点详细梳理
服务器·前端·经验分享·笔记·php
2401_877274248 小时前
从匿名管道到 Master-Slave 进程池:Linux 进程间通信深度实践
linux·服务器·c++
feng_you_ying_li8 小时前
linux之用户的权限详解(4)
linux·运维·服务器
二进制person9 小时前
JavaEE初阶 --网络编程
linux·服务器·网络
Oll Correct9 小时前
实验八:验证以太网交换机的生成树协议STP
网络·笔记
Irissgwe10 小时前
进程间通信
linux·服务器·网络·c++·进程间通信
岁岁种桃花儿11 小时前
AI超级智能开发系列从入门到上天第四篇:AI应用方案设计
java·服务器·开发语言