C++ 20 协程 之 Hello World(二)

C++ 20 协程 之 Hello World(二)

了解co_await的使用。

可等待对象awaitable

使用co_await关键字必须用于返回值为awaitable的对象的函数,如下图所示:

struct awaitable {
	bool await_ready();
	void await_suspend(coroutine_handle<>);
	void await_resume();
};

调用如下:

co_await awaitable{};

等价于

if(!awaitable.await_ready()){
	awaitable.await_suspend(); // 挂起协程
}
awaitable.await_resume(); // 恢复协程

awaitable对象的await_ready函数判断协程是否就绪,如果就绪的话直接恢复协程,继续向下执行;如果未就绪的话,需要执行await_suspend函数的逻辑,在实践中可能是一些耗时逻辑,如网络请求、IO操作、复杂CPU计算等,等待await_suspend函数的逻辑执行完成即可恢复协程让程序继续向下执行。

Hello World co_await的使用

下面是最简单的co_await的使用的Hello World版本。

struct HelloCoroutine {
public:
    struct promise_type {
    public:
        promise_type(){
            std::cout << "promise_type constructed\n";
        }
        ~promise_type(){
            std::cout << "promise_type destructed\n";
        }
        HelloCoroutine get_return_object(){
            std::cout << "get_return_object\n";
            return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
        }
        std::suspend_always initial_suspend(){
            std::cout << "initial_suspend\n";
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            std::cout << "final_suspend\n";
            return {};
        }
        void return_void(){
            std::cout << "return_void\n";
        }
        void unhandled_exception(){
            std::cerr << "Coroutine encountered an exception.\n";
        }
    };
    struct awaitable {
        bool await_ready() const noexcept { 
            std::cout << "await_ready\n";
            return false;
         }
        void await_suspend(std::coroutine_handle<promise_type> h) const noexcept {
            std::cout << "await_suspend\n";
            h.resume();
        }
        void await_resume() const noexcept {
            std::cout << "await_resume\n";
        }
    };
    HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
        std::cout << "HelloCoroutine constructed\n";
    }
    ~HelloCoroutine() {
        std::cout << "HelloCoroutine destructed\n";
        handle.destroy();
    }
    void resume() { // 1
        if (!handle.done()) {
            handle.resume();
            std::cout << "Coroutine resumed\n";
        }
    }
private:
    std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
    std::cout << "Hello, Coroutine before!" << std::endl;
    co_await HelloCoroutine::awaitable{};
    std::cout << "Hello, Coroutine after!" << std::endl;
}
void learn01(){
    HelloCoroutine hello = helloCoroutine();
    hello.resume();
}

没有什么好分析的HelloCoroutine对象的resume方法代表者开启协程,如果没有这个方法,则代表着这个协程被创建,但是协程没有被启动。
co_await返回值版本
实现如下功能:
一秒钟之后返回a+b的值。

struct HelloCoroutine {
public:
    struct promise_type {
    public:
        promise_type(){
            std::cout << "promise_type constructed\n";
        }
        ~promise_type(){
            std::cout << "promise_type destructed\n";
        }
        HelloCoroutine get_return_object(){
            std::cout << "get_return_object\n";
            return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
        }
        std::suspend_always initial_suspend(){
            std::cout << "initial_suspend\n";
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            std::cout << "final_suspend\n";
            return {};
        }
        void return_void(){
            std::cout << "return_void\n";
        }
        void unhandled_exception(){
            std::cerr << "Coroutine encountered an exception.\n";
        }
    };
    struct awaitable {
        private:
        int a, b, sum;
        public:
        awaitable(const int a, const int b) : a(a), b(b) {
            std::cout << "awaitable constructed\n";
        }
        ~awaitable(){
            std::cout << "awaitable destructed\n";
        }
        bool await_ready() const noexcept { 
            std::cout << "await_ready\n";
            return false;
         }
        void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
            std::cout << "await_suspend\n";
            // 在后台线程中延迟后恢复协程
            std::thread([this, h, delay = 1000]() -> void {
                std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
                std::cout << "计算完成,恢复协程\n";
                sum = a + b; // 模拟计算结果
                h.resume(); // 自动恢复协程
            }).join();
        }
        int await_resume() const noexcept {
            std::cout << "await_resume\n";
            return sum;
        }
    };
    HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
        std::cout << "HelloCoroutine constructed\n";
    }
    ~HelloCoroutine() {
        std::cout << "HelloCoroutine destructed\n";
        handle.destroy();
    }
    void resume() {
        if (!handle.done()) {
            handle.resume();
            std::cout << "Coroutine resumed\n";
        }
    }
private:
    std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
    std::cout << "Hello, Coroutine before!" << std::endl;
    auto result = co_await HelloCoroutine::awaitable(1, 2);
    std::cout << "Hello, Coroutine after! a: " << result << std::endl;
}
void learn01(){
    HelloCoroutine hello = helloCoroutine();
    hello.resume(); // 开启协程
}

返回结果版本

struct HelloCoroutine {
public:
    struct promise_type {
    private:
        int value = 0;
    public:
        promise_type(){
            std::cout << "promise_type constructed\n";
        }
        ~promise_type(){
            std::cout << "promise_type destructed\n";
        }
        HelloCoroutine get_return_object(){
            std::cout << "get_return_object\n";
            return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
        }
        std::suspend_always initial_suspend(){
            std::cout << "initial_suspend\n";
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            std::cout << "final_suspend\n";
            return {};
        }
        void return_value(int value){
            std::cout << "return_void\n";
            this->value = value;
        }
        void unhandled_exception(){
            std::cerr << "Coroutine encountered an exception.\n";
        }
        int getValue() const { return value; }
    };
    struct awaitable {
        private:
        int a, b, sum;
        public:
        awaitable(const int a, const int b) : a(a), b(b) {
            std::cout << "awaitable constructed\n";
        }
        ~awaitable(){
            std::cout << "awaitable destructed\n";
        }
        bool await_ready() const noexcept { 
            std::cout << "await_ready\n";
            return false;
         }
        void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
            std::cout << "await_suspend\n";
            // 在后台线程中延迟后恢复协程
            std::thread([this, h, delay = 1000]() -> void {
                std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
                std::cout << "计算完成,恢复协程\n";
                sum = a + b; // 模拟计算结果
                h.resume(); // 自动恢复协程
            }).detach(); // 分离线程,使其在后台运行
        }
        int await_resume() noexcept {
            std::cout << "await_resume\n";
            return sum; // 获取计算结果
        }
    };
    HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
        std::cout << "HelloCoroutine constructed\n";
    }
    ~HelloCoroutine() {
        std::cout << "HelloCoroutine destructed\n";
        handle.destroy();
    }
    void resume() {
        if (!handle.done()) {
            handle.resume();
            std::cout << "Coroutine resumed\n";
        }
    }
    int getValue() const {
        return handle.promise().getValue();
    }
private:
    std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
    std::cout << "Hello, Coroutine before!" << std::endl;
    auto result = co_await HelloCoroutine::awaitable(1, 2);
    std::cout << "Hello, Coroutine after! a: " << result << std::endl;
    co_return result;
}
void learn01(){
    HelloCoroutine hello = helloCoroutine();
    hello.resume(); // 开启协程
    std::cout << "Coroutine returned value: " << hello.getValue() << std::endl;
}

查看如下代码,思考以下是异步还是同步?这样做是否有问题?

struct HelloCoroutine {
public:
    struct promise_type {
    public:
        promise_type(){
            std::cout << "promise_type constructed\n";
        }
        ~promise_type(){
            std::cout << "promise_type destructed\n";
        }
        HelloCoroutine get_return_object(){
            std::cout << "get_return_object\n";
            return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
        }
        std::suspend_always initial_suspend(){
            std::cout << "initial_suspend\n";
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            std::cout << "final_suspend\n";
            return {};
        }
        void return_void(){
            std::cout << "return_void\n";
        }
        void unhandled_exception(){
            std::cerr << "Coroutine encountered an exception.\n";
        }
    };
    struct awaitable {
    private:
        int a, b, sum;
    public:
        awaitable(const int a, const int b) : a(a), b(b) {
            std::cout << "awaitable constructed\n";
        }
        ~awaitable(){
            std::cout << "awaitable destructed\n";
        }
        bool await_ready() const noexcept { 
            std::cout << "await_ready\n";
            return false;
        }
        void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
            std::cout << "await_suspend\n";
            // 在后台线程中延迟后恢复协程
            std::thread([this, h, delay = 1000]() -> void {
                std::cout << "Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
                std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
                std::cout << "计算完成,恢复协程\n";
                sum = a + b;
                h.resume(); // 自动恢复协程
            }).join(); // 分离线程,使其在后台运行
        }
        int await_resume() noexcept {
            std::cout << "await_resume\n";
            std::cout << "await_resume Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
            return sum;
        }
    };
    HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
        std::cout << "HelloCoroutine constructed\n";
    }
    ~HelloCoroutine() {
        std::cout << "HelloCoroutine destructed\n";
        handle.destroy();
    }
    void resume() {
        if (!handle.done()) {
            handle.resume();
            std::cout << "Coroutine resumed\n";
        }
    }
private:
    std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
    std::cout << "Hello, Coroutine before!" << std::endl;
    int result = co_await HelloCoroutine::awaitable(1, 2);
    std::cout << "Hello, Coroutine after result1: " << result << std::endl;
    result = co_await HelloCoroutine::awaitable(1, 2);
    std::cout << "Hello, Coroutine after result2: " << result << std::endl;
    co_return;
}
void learn01(){
    HelloCoroutine hello = helloCoroutine();
    hello.resume(); // 开启协程
    std::cout << "Coroutine returned value thread id: " << std::this_thread::get_id()<< std::endl;
}

并发计算

struct HelloCoroutine {
public:
    struct promise_type {
    public:
        promise_type(){
            std::cout << "promise_type constructed\n";
        }
        ~promise_type(){
            std::cout << "promise_type destructed\n";
        }
        HelloCoroutine get_return_object(){
            std::cout << "get_return_object\n";
            return HelloCoroutine(std::coroutine_handle<promise_type>::from_promise(*this)); // 解引用
        }
        std::suspend_always initial_suspend(){
            std::cout << "initial_suspend\n";
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            std::cout << "final_suspend\n";
            return {};
        }
        void return_void(){
            std::cout << "return_void\n";
        }
        void unhandled_exception(){
            std::cerr << "Coroutine encountered an exception.\n";
        }
    };
    struct awaitable {
    private:
        int a, b;
    public:
        std::promise<int> promise;
        awaitable(const int a, const int b) : a(a), b(b) {
            std::cout << "awaitable constructed\n";
        }
        ~awaitable(){
            std::cout << "awaitable destructed\n";
        }
        bool await_ready() const noexcept { 
            std::cout << "await_ready\n";
            return false;
        }
        void await_suspend(std::coroutine_handle<promise_type> h) noexcept {
            std::cout << "await_suspend\n";
            // 在后台线程中延迟后恢复协程
            std::thread([this, h, delay = 1000]() -> void {
                std::cout << "Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
                std::this_thread::sleep_for(std::chrono::milliseconds(delay)); // []()->void::delay delay 是闭包当中的一个属性
                std::cout << "计算完成,恢复协程\n";
                promise.set_value(a + b);
                h.resume(); // 自动恢复协程
            }).detach(); // 分离线程,使其在后台运行
        }
        std::future<int> await_resume() noexcept {
            std::cout << "await_resume\n";
            std::cout << "await_resume Starting background computation in thread id: " << std::this_thread::get_id() << "\n";
            return promise.get_future(); // 获取结果,阻塞等待
        }
    };
    HelloCoroutine(std::coroutine_handle<promise_type> coroutineHandle) : handle(coroutineHandle) {
        std::cout << "HelloCoroutine constructed\n";
    }
    ~HelloCoroutine() {
        std::cout << "HelloCoroutine destructed\n";
        handle.destroy();
    }
    void resume() {
        if (!handle.done()) {
            handle.resume();
            std::cout << "Coroutine resumed\n";
        }
    }
private:
    std::coroutine_handle<promise_type> handle; // 指向协程帧
};
HelloCoroutine helloCoroutine(){
    std::cout << "Hello, Coroutine before!" << std::endl;
    auto result1 = co_await HelloCoroutine::awaitable(1, 2);
    auto result2 = co_await HelloCoroutine::awaitable(3, 4);
    std::cout << "Coroutine results: " << result1.get() << ", " << result2.get() << std::endl;
    std::cout << "helloCoroutine returned value thread id: " << std::this_thread::get_id()<< std::endl;
    co_return;
}
void learn01(){
    HelloCoroutine hello = helloCoroutine();
    hello.resume(); // 开启协程
    std::cout << "Coroutine returned value thread id: " << std::this_thread::get_id()<< std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(3000)); 
}
posted @ 2025-09-02 23:58  爱情丶眨眼而去  阅读(9)  评论(0)    收藏  举报