c++协程相关

42 阅读1分钟

协程中断示例

标志位

#include <QApplication>
#include <QPushButton>
#include <QDebug>
#include <QThread>
#include <coroutine>
#include <atomic>
#include <iostream>

struct HelloCoroutine {
    struct HelloPromise {
        HelloCoroutine get_return_object() {
            return std::coroutine_handle<HelloPromise>::from_promise(*this);
        }
        std::suspend_never initial_suspend() {
            qDebug() << "==============initial_suspend==============";
            return {};
        }
        std::suspend_never final_suspend() noexcept {
            qDebug() << "==============final_suspend==============";
            return {};
        }
        void unhandled_exception() {}
        void return_void() {
            qDebug() << "==============return_value==============";
        }
    };

    using promise_type = HelloPromise;
    HelloCoroutine(std::coroutine_handle<HelloPromise> h) : handle(h) {}

    ~HelloCoroutine() {
        if (handle) {
            handle.destroy();
        }
    }

    std::coroutine_handle<HelloPromise> handle;
};

auto add(int a, int b, std::atomic<bool>& cancelFlag) {
    struct AddAwaitable {
        int a, b;
        std::atomic<bool>& cancelFlag;

        bool await_ready() const noexcept {
            return false;
        }

        void await_suspend(std::coroutine_handle<> h) const noexcept {
            QThread::create([this, h](){
                QThread::sleep(1); // 使用 sleep 而不是 msleep,因为这里是秒级
                if (!cancelFlag.load()) { // 检查取消标志
                    h.resume();
                } else {
                    qDebug() << "================cancel==================";
                    h.resume();
                }
            })->start();
        }

        int await_resume() const noexcept {
            return a + b;
        }
    };
    return AddAwaitable{a, b, cancelFlag};
}

HelloCoroutine hello(std::atomic<bool>& cancelFlag) {
    for (int i = 1; i <= 10; i++) {
//        if (cancelFlag.load()) { // 检查取消标志
//            qDebug() << "Coroutine cancelled";
//            co_return;
//        }
        int res = co_await add(i, 0, cancelFlag);
        qDebug() << "res = " << res;
    }
}

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QPushButton button("Cancel Coroutine", nullptr);
    button.resize(200, 100);
    button.show();

    std::atomic<bool> cancelFlag(false);
    HelloCoroutine coro = hello(cancelFlag);

    QObject::connect(&button, &QPushButton::clicked, [&cancelFlag](){
        cancelFlag.store(true); // 设置取消标志
    });

    QThread::create([&](){
        QThread::sleep(3);
        cancelFlag.store(true); // 或者在另一个线程中设置取消标志
    })->start();

    return QApplication::exec();
}

异常

#include <QApplication>
#include <QPushButton>
#include <QDebug>
#include <QThread>
#include <coroutine>
#include <atomic>
#include <iostream>

#include <iostream>
#include <coroutine>
#include <stdexcept>

// 协程返回类型
struct Task {
    struct promise_type {
        Task get_return_object() { return {}; }
        std::suspend_never initial_suspend() {
            qDebug() << "=============initial_suspend=======================";
            return {};
        }
        std::suspend_never final_suspend() noexcept {
            qDebug() << "=============final_suspend=======================";
            return {};
        }
        void unhandled_exception() {
            qDebug() << "================unhandled_exception===============";
//            std::terminate();
        }
        void return_void() {}
    };
};

//co_await method形式, eg: int result = co_await add(1, 2);
auto add(int a, int b) {
    struct awaitable {
        int a, b, result;
        bool await_ready() {
            return false;
        }
        void await_suspend(std::coroutine_handle<> h) {
            QThread::create([=](){
                QThread::sleep(1);
                result = a + b; //耗时操作
                h.resume();
            })->start();
        }
        int await_resume() {
            return result;
        }
    };
    return awaitable{a, b};
}

// 协程函数
Task my_coroutine() {
    for (int i = 1; i <= 10; i++) {
        int res = co_await add(i, 0);
        qDebug() << "res = " << res;
        if (i == 5) {
            throw std::runtime_error("An error occurred in coroutine");
        }
    }
}

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QPushButton button("Cancel Coroutine", nullptr);
    button.resize(200, 100);
    button.show();

    my_coroutine();

    return QApplication::exec();
}