C++20新特性:协程

1. 协程(Coroutine)简介

协程是一类特殊的函数,它具备独特的执行特性,能够在执行过程里暂停,并在后续合适的时机恢复执行。这与普通函数有着显著区别,普通函数一旦开始执行就会持续运行直至结束,而协程却可以在任意位置选择挂起(yield),将程序的控制权交还给调用者,并且它还能巧妙地保留自身的状态。C++20 引入了对协程的原生支持,这种特性使得协程在异步编程、生成器以及状态机等方面有着更加优越的性能。

2. 协程的核心概念

挂起(Suspend)

协程在执行过程中,能够灵活地选择挂起,此时它会将控制权返回给调用者。而且在挂起的瞬间,协程的所有状态,包括局部变量的值以及执行位置等关键信息,都会被妥善保存下来。

恢复(Resume)

协程可以从之前挂起的位置无缝恢复执行,就像时间倒流后继续前行一样,接着未完成的任务继续运行。

协程帧(Coroutine Frame)

协程的各种状态,如局部变量的值以及挂起点等,都被存储在协程帧之中。协程帧在堆上进行分配,它的生命周期则由协程库进行统一管理。

协程句柄(Coroutine Handle)

协程句柄是控制协程执行的关键“钥匙”,通过它可以实现对协程的各种操作,比如挂起、恢复以及销毁等。

3. C++20 协程的关键组件

co_await

这个关键字主要用于挂起协程,让协程等待某个特定的操作完成。这里所等待的操作类型丰富多样,可以是异步 I/O 操作、定时器事件,也可以是某个任务的完成等。

co_yield

co_yield 的作用是生成一个值,同时将协程挂起。在实际应用中,它常常被用于实现生成器(Generator)功能。

co_return

当协程执行到 co_return 时,它会从协程中返回一个值,同时宣告协程的执行结束。

协程类型

协程函数在返回值方面有一定要求,它必须返回一个符合协程接口的类型,比如 std::future、generator 等。

4. 协程示例

示例 1:简单的协程(生成器)

下面这个示例实现了一个生成器,它能够生成一系列整数。

#include <iostream>
#include <coroutine>
​
// 定义一个生成器类型
template<typename T>
struct Generator {
    struct promise_type {
        T value; // 生成的值
        Generator get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; }
        std::suspend_always initial_suspend() { return {}; } // 初始挂起
        std::suspend_always final_suspend() noexcept { return {}; } // 最终挂起
        void unhandled_exception() { std::terminate(); } // 异常处理
        std::suspend_always yield_value(T val) { value = val; return {}; } // 挂起并返回值
        void return_void() {} // 协程结束
    };
​
    std::coroutine_handle<promise_type> handle;
​
    explicit Generator(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~Generator() { if (handle) handle.destroy(); } // 销毁协程
​
    T next() {
        handle.resume(); // 恢复协程
        return handle.promise().value; // 返回生成的值
    }
};
​
// 定义一个生成器协程
Generator<int> range(int start, int end) {
    for (int i = start; i <= end; ++i) {
        co_yield i; // 生成值并挂起
    }
}
​
int main() {
    auto gen = range(1, 5); // 创建生成器
    for (int i = 0; i < 5; ++i) {
        std::cout << gen.next() << std::endl; // 获取生成的值
    }
    return 0;
}

示例 2:异步任务

接下来的这个示例实现了一个简单的异步任务,用于模拟实际中的异步操作。

#include <iostream>
#include <coroutine>
#include <thread>
#include <chrono>
​
// 定义一个异步任务类型
struct AsyncTask {
    struct promise_type {
        int value; // 任务的结果
        AsyncTask get_return_object() { return AsyncTask{std::coroutine_handle<promise_type>::from_promise(*this)}; }
        std::suspend_always initial_suspend() { return {}; } // 初始挂起
        std::suspend_always final_suspend() noexcept { return {}; } // 最终挂起
        void unhandled_exception() { std::terminate(); } // 异常处理
        void return_value(int val) { value = val; } // 返回值
    };
​
    std::coroutine_handle<promise_type> handle;
​
    explicit AsyncTask(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~AsyncTask() { if (handle) handle.destroy(); } // 销毁协程
​
    int get() {
        handle.resume(); // 恢复协程
        return handle.promise().value; // 返回结果
    }
};
​
// 定义一个异步任务协程
AsyncTask computeAsync() {
    std::cout << "Starting async computation..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
    co_return 42; // 返回结果
}
​
int main() {
    auto task = computeAsync(); // 创建异步任务
    std::cout << "Waiting for result..." << std::endl;
    int result = task.get(); // 获取结果
    std::cout << "Result: " << result << std::endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值