找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1095

积分

0

好友

139

主题
发表于 8 小时前 | 查看: 2| 回复: 0

协程是 C++20 引入的一种能暂停执行、保留状态并在后续恢复执行的函数,突破了传统函数 “一次性执行完毕” 的线性执行模式。

先看代码,后文有说明。

使用示例

```c++
/**

  • C++20 协程示例:co_await 与自定义 Awaitable
  • 编译:需 -std=c++20 -fcoroutines
  • 运行:./coroutine_await
  • 演示如何实现一个最小 Task 类型,以及自定义 Awaitable(SleepAwaitable)的用法。
    */

    include <chrono>

    include <coroutine>

    include <iostream>

    include <thread>

    // ========== 关键点1:自定义 Awaitable 需实现三个接口 ==========
    // co_await expr 时,expr 必须是 Awaitable(或通过 operator co_await 转换)
    struct SleepAwaitable
    {
    std::chrono::milliseconds duration;
    // 若为 true,不挂起,直接继续执行;这里 0 及以下不挂起
    bool await_ready() const { return duration.count() <= 0; }
    // ========== 关键点2:挂起时调用,h 就是当前协程的句柄 ==========
    // 在此把 h 交给“谁”来在将来 resume:这里用线程 sleep 后 resume
    // 实际项目中可改为:注册到 I/O 完成回调、定时器、线程池等
    void await_suspend(std::coroutine_handle<> h) const
    {
    std::thread([h, d = duration]() {
    std::this_thread::sleep_for(d);
    h.resume(); // 在“就绪”后恢复协程
    }).detach();
    }
    // 恢复时调用;返回值即为 co_await 表达式的值,这里为 void
    void await_resume() {}
    };
    // ========== 关键点3:Task 通过 promise_type 与协程绑定 ==========
    // 支持在协程内使用 co_await,并让调用方能启动/等待协程
    struct Task
    {
    struct promise_type
    {
    Task get_return_object()
    {
    return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
    }
    // 初始挂起:协程创建后先不执行,等有人 resume 再跑
    std::suspend_always initial_suspend() { return {}; }
    std::suspend_always final_suspend() noexcept { return {}; }
    void return_void() {}
    void unhandled_exception() { std::terminate(); }
    };
    std::coroutine_handle<promise_type> handle;
    void start() { handle.resume(); }
    bool done() const { return handle.done(); }
    ~Task()
    {
    if (handle)
    handle.destroy();
    }
    };
    // ========== 关键点4:协程内 co_await Awaitable,会挂起并在 Awaitable 恢复时继续 ==========
    Task run_delayed_echo()
    {
    std::cout << "  [协程] 开始,即将挂起 500ms..." << std::endl;
    co_await SleepAwaitable{std::chrono::milliseconds(500)}; // 挂起约 500ms 后从此行之后恢复
    std::cout << "  [协程] 恢复执行,再挂起 300ms..." << std::endl;
    co_await SleepAwaitable{std::chrono::milliseconds(300)};
    std::cout << "  [协程] 再次恢复,结束。" << std::endl;
    co_return; // 协程正常结束,由 promise_type::return_void() 处理
    }
    int main()
    {
    std::cout << "=== co_await 自定义 Awaitable(Sleep)===" << std::endl;
    std::cout << "[main] 创建协程并启动" << std::endl;
    Task t = run_delayed_echo();
    t.start();
    // 第一次 resume:协程跑到第一个 co_await 后挂起
    // 协程在另一线程里被 SleepAwaitable 恢复,主线程简单等待其结束
    while (!t.done())
    {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    std::cout << "[main] 协程已结束" << std::endl;
    return 0;
    }

输出如下

=== co_await 自定义 Awaitable(Sleep)===
[main] 创建协程并启动
  [协程] 开始,即将挂起 500ms...
  [协程] 恢复执行,再挂起 300ms...
  [协程] 再次恢复,结束。
[main] 协程已结束

协程的核心定义

协程本质是可中断的函数,通过 co_awaitco_yieldco_return 等关键字实现执行流的灵活控制。

  • co_await 是协程暂停的核心入口,其操作对象需满足 “Awaitable” 接口(示例中 SleepAwaitable),协程执行到 co_await 时会暂停,直到 Awaitable 对象触发恢复;
  • 协程的行为由 promise_type(示例中 Task::promise_type)管控,它定义了协程的创建(get_return_object)、初始 / 最终挂起(initial_suspend/final_suspend)、返回值处理(return_void)等核心规则,是协程与外部交互的桥梁;
  • 协程句柄(std::coroutine_handle)是操控协程的 “手柄”,可通过 resume() 恢复执行、done() 判断是否结束、destroy() 释放资源,示例中 Task 类封装了句柄,提供 start() 启动协程的便捷接口。

协程的关键特性

  • 可控的挂起与恢复:协程可在任意 co_await 处主动挂起,且挂起时会保留当前栈帧和变量状态(示例中 run_delayed_echo 协程两次挂起后,恢复时能从挂起行继续执行),无需像线程那样重新初始化上下文;
  • 非阻塞等待:通过自定义 Awaitable(如 SleepAwaitable),协程挂起时不会阻塞当前线程,示例中挂起逻辑被移交到新线程执行 sleep_for,主线程可继续做其他操作,仅通过轮询 done() 等待协程结束,相比传统阻塞等待更高效,这对于设计高并发的后端系统架构很有启发;
  • 轻量级:协程的挂起 / 恢复开销远低于线程切换,示例中通过协程实现的延迟执行,无需创建多个重量级线程,仅通过协程句柄的 resume() 即可恢复执行;
  • 自定义等待逻辑:Awaitable 对象可灵活定制挂起后的行为(示例中是延迟恢复,实际可扩展为 I/O 完成回调、定时器触发、线程池调度等),只需实现 await_ready()(判断是否需要挂起)、await_suspend()(挂起时的逻辑,如移交协程句柄)、await_resume()(恢复时的返回值处理)三个接口。深入理解这种机制,是掌握现代 C/C++ 高级编程的关键一步。

通过上面的代码与解析,我们可以直观地感受到 C++20 协程带来的执行流程控制能力。从自定义 Awaitable 的实现,到 Task 类型对协程生命周期的封装,每一步都体现了标准库设计的灵活性。如果你对更多 C++ 高级特性和并发编程实践感兴趣,欢迎到云栈社区与其他开发者交流探讨。

玫瑰花表情




上一篇:ASP.NET月子会所ERP平台SQL注入与文件上传0day代码审计实战解析
下一篇:深度解析:工业革命四次演进的技术特征、关键节点与未来影响
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-10 18:06 , Processed in 0.463944 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表