c++如何自定义一个co_await表达式实现协程awaiter

来源:站长工具作者:重启一下头衔:草根站长
导读:本期聚焦于小伙伴创作的《c++如何自定义一个co_await表达式实现协程awaiter》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《c++如何自定义一个co_await表达式实现协程awaiter》有用,将其分享出去将是对创作者最好的鼓励。

c++20引入的协程特性为异步编程提供了更简洁的语法支持,co_await作为协程中用于挂起当前协程并等待操作完成的关键字,其背后依赖的是awaiter对象的实现。自定义co_await表达式本质上就是实现一个符合awaiter接口要求的类型,让该类型的实例能够被co_await正确调用。

c++如何自定义一个co_await表达式实现协程awaiter

awaiter的核心接口要求

一个类型要成为合法的awaiter,必须实现三个特定的成员函数,这三个函数分别对应协程挂起、等待完成判断、恢复执行三个阶段的逻辑:

  • await_ready:返回bool类型,用于判断是否需要挂起协程。如果返回true,说明等待的操作已经就绪,协程不需要挂起,直接继续执行后续逻辑;如果返回false,协程将被挂起。
  • await_suspend:接受一个协程句柄作为参数,在协程挂起后调用。可以在该函数中执行注册回调、保存协程句柄等操作,返回值可以是bool、void或者协程句柄,用于控制协程挂起后的行为。
  • await_resume:在协程恢复执行后调用,返回的值就是整个co_await表达式的结果。可以在该函数中返回等待操作的最终结果,或者处理等待完成后的收尾逻辑。

自定义简单awaiter实现示例

下面实现一个简单的延时awaiter,当co_await该awaiter时,协程会挂起指定的时间后再恢复执行,首先定义awaiter类型:

#include <coroutine>
#include <thread>
#include <chrono>
#include <iostream>

// 自定义延时awaiter类型
struct DelayAwaiter {
    // 延时时长,单位毫秒
    int delay_ms;

    // 构造函数,传入需要延时的毫秒数
    explicit DelayAwaiter(int ms) : delay_ms(ms) {}

    // 判断是否需要挂起,这里默认返回false,即总是挂起协程等待延时完成
    bool await_ready() const noexcept {
        return false;
    }

    // 协程挂起后执行的逻辑,这里启动一个线程延时后恢复协程
    void await_suspend(std::coroutine_handle<> handle) const noexcept {
        // 启动新线程执行延时逻辑
        std::thread([handle, this]() {
            // 睡眠指定时长
            std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
            // 延时完成,恢复协程执行
            handle.resume();
        }).detach();
    }

    // 协程恢复后执行的逻辑,这里返回void,也可以返回需要的结果
    void await_resume() const noexcept {}
};

配合协程使用自定义awaiter

定义好awaiter之后,需要在协程函数中使用co_await调用它,首先定义一个简单的协程返回类型,用于支持协程的基本运行:

// 简单的协程返回类型,仅支持基本协程逻辑
struct SimpleTask {
    struct promise_type {
        SimpleTask get_return_object() { return SimpleTask{}; }
        std::coroutine_handle<> initial_suspend() { return std::suspend_never{}; }
        std::coroutine_handle<> final_suspend() noexcept { return std::suspend_never{}; }
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };
};

// 协程函数,使用自定义的DelayAwaiter
SimpleTask test_coroutine() {
    std::cout << "协程开始执行" << std::endl;
    // co_await自定义的延时awaiter,挂起1秒
    co_await DelayAwaiter(1000);
    std::cout << "协程恢复执行,延时完成" << std::endl;
}

在main函数中调用该协程,可以看到输出结果符合预期:

int main() {
    // 启动协程
    test_coroutine();
    // 主线程等待足够时间,避免协程未执行完程序就退出
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return 0;
}

awaiter的进阶实现注意事项

在实际开发中,自定义awaiter还需要注意几个问题:

异常安全处理

await_suspend函数中如果可能抛出异常,需要做好异常处理,避免异常传递到协程外部导致程序崩溃。如果await_suspend返回bool类型,返回false的话协程不会挂起,会直接继续执行后续逻辑。

协程句柄的生命周期管理

在await_suspend中保存协程句柄时,要确保在协程恢复之前句柄是有效的,不能保存已经销毁的协程的句柄,否则调用resume会导致未定义行为。

返回值的处理

await_resume的返回类型就是co_await表达式的类型,如果需要返回等待的结果,比如异步读取的数据,可以在await_resume中返回对应的值,协程中co_await的接收变量就可以拿到这个结果。

通过上述步骤,就可以根据自己的需求自定义不同的awaiter,实现各类异步等待场景的co_await表达式,充分发挥c++协程的异步编程优势。

c++coroutineco_awaitawaiter修改时间:2026-07-23 20:54:16

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。