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 对象。
相关推荐
九河云32 分钟前
如何选择适合的AWS EC2实例类型
服务器·云计算·aws
sun00770041 分钟前
MISRA C++ 2023 编码标准&规范
c++20
Tassel_YUE2 小时前
网络自动化04:python实现ACL匹配信息(主机与主机信息)
网络·python·自动化
其乐无涯2 小时前
服务器技术(一)--Linux基础入门
linux·运维·服务器
Diamond技术流2 小时前
从0开始学习Linux——网络配置
linux·运维·网络·学习·安全·centos
写bug的小屁孩2 小时前
前后端交互接口(三)
运维·服务器·数据库·windows·用户界面·qt6.3
斑布斑布2 小时前
【linux学习2】linux基本命令行操作总结
linux·运维·服务器·学习
紅色彼岸花2 小时前
第六章:DNS域名解析服务器
运维·服务器
Spring_java_gg2 小时前
如何抵御 Linux 服务器黑客威胁和攻击
linux·服务器·网络·安全·web安全
✿ ༺ ོIT技术༻2 小时前
Linux:认识文件系统
linux·运维·服务器