协程啊啊啊

协程 (C++20) - cppreference.com

#include <iostream>  
#include <future>  
#include <coroutine>  
#include <string>  
#include <iostream>  
#include <future>  
#include <coroutine>  
#include <thread>

// 定义协程的返回类型  
struct MyTask {  
    struct promise_type {  
        MyTask get_return_object() {  
            return {std::coroutine_handle<promise_type>::from_promise(*this)};  
        }  
        std::suspend_never initial_suspend() { return {}; }  
        std::suspend_always final_suspend() noexcept { return {}; }  
        void return_void() {}  
        void unhandled_exception() {  
            std::cerr << "Unhandled exception in coroutine\n";  
            std::terminate();  
        }  
  
        std::future<void> get_future() {  
            return result.get_future();  
        }  
  
        std::promise<void> result;  
    };  
  
    std::coroutine_handle<promise_type> coro;  
  
    ~MyTask() {  
        if (coro) coro.destroy();  
    }  
  
    MyTask(const MyTask&) = delete;  
    MyTask& operator=(const MyTask&) = delete;  
  
    MyTask(MyTask&& other) noexcept  
        : coro(std::exchange(other.coro, {})) {}  
  
    MyTask& operator=(MyTask&& other) noexcept {  
        if (this != &other) {  
            coro = std::exchange(other.coro, {});  
        }  
        return *this;  
    }  
  
    void start() {  
        if (coro) coro.resume();  
    }  
  
    void wait() 
    {  
     if (coro) coro.promise().get_future().wait();  
    }  
  
private:  
    MyTask(std::coroutine_handle<promise_type> h) : coro(h) {}  
  
    friend struct promise_type; // 允许 promise_type 访问私有构造函数  
};  
  
// 协程函数  
MyTask myCoroutine() {  
    std::cout << "Coroutine started\n";  
    co_await std::suspend_always{}; // 协程的“暂停点”(实际不暂停)  
    std::cout << "Coroutine resumed\n";  
}  
  
int main() {  
    MyTask task = myCoroutine();  
    std::cout << "Launching coroutine...\n";  
    task.start(); // 启动协程  
  
    // 做一些其他事情...  
    std::this_thread::sleep_for(std::chrono::seconds(1));  
  
    task.wait(); // 等待协程完成  
    std::cout << "Coroutine completed\n";  
  
    return 0;  
}
  • #include <coroutine>
    #include <iostream>
    #include <stdexcept>
    #include <thread>
     
    struct awaitable
    {
        std::thread* p_out;
        bool await_ready() 
        { 
            printf("ready\n");
            return false; 
        }
        void await_suspend(std::coroutine_handle<> h) // 这个是协程挂起时,要执行的操作
        {
            std::thread& out = *p_out;
            if (out.joinable())
                throw std::runtime_error("thread 输出参数非空"); 
            out = std::thread([h] 
            { 
                sleep(5);
                printf("开始执行唤醒%ld\n", std::this_thread::get_id());
                h.resume();     // !!这里其实就是恢复协程,执行co_await switch_to_new_thread下面的代码
                sleep(2);
                printf("异步线程退出\n");
            });
            printf("新线程id:%ld 当前线程id:%ld\n", out.get_id(), std::this_thread::get_id());
            std::cout << "2新线程 ID:" << out.get_id() << '\n';
        }
        void await_resume() 
        {
            printf("await_resume\n");
        }
    };
    awaitable switch_to_new_thread(std::thread& out)
    {
       
        printf("切换线程\n");
        return awaitable{&out};
    }
     
    struct task
    {
        struct promise_type
        {
            int value;
            promise_type()
            {
                printf("promise_type构造函数\n");
            }
            task get_return_object() 
            { 
                printf("get_return_object\n");
                return { std::coroutine_handle<promise_type>::from_promise(*this) }; 
            }
            std::suspend_never initial_suspend() 
            { 
                printf("initial_suspend\n");
                return {}; 
            }
            std::suspend_never final_suspend() noexcept 
            { 
                printf("final_suspend\n");
                return {}; 
            }
            void return_value(int v) 
            {
                printf("return_value: %d\n", v);
                value = v;
            }
            void unhandled_exception() 
            {
                printf("unhandled_exception\n");
            }
        };
        std::coroutine_handle<promise_type> coro_handle;
    
        task(std::coroutine_handle<promise_type> h) : coro_handle(h) {}
        ~task() { coro_handle.destroy(); }
        int get() { return coro_handle.promise().value; }
    };
     
    task resuming_on_new_thread(std::thread& out)
    {
     
        printf("进入到了resuming_on_new_thread\n");
        std::cout << "协程开始,线程 ID:" << std::this_thread::get_id() << '\n';
        co_await switch_to_new_thread(out);
        std::cout << "协程恢复,线程 ID:" << std::this_thread::get_id() << '\n';
        co_return 42; // 返回一个值
     
    }
    // 协程函数,使用 co_return 返回一个整数值
    task example_coroutine()
    {
        co_return 123; // 返回一个整数值
    }
    
     
    int main()
    {
        // std::thread out;
        // auto t = resuming_on_new_thread(out);
        // std::cout << "!!这里是同步立马执行,协程只会恢复到resuming_on_new_thread函数" << std::this_thread::get_id() << '\n';
        // out.join(); // 等待新线程完成
        // std::cout << "协程返回的值是:" << t.get() << '\n';
    
    
        auto t = example_coroutine();
        std::cout << "协程返回的值是:" << t.get() << '\n';
    }

  • co_await 表达式——用于暂停执行,直到恢复:co_await 后面通常跟随一个可等待对象(awaitable),这个对象必须符合特定的条件,使得编译器能够正确地生成协程相关的代码

这个对象必须实现以下三个函数或者函数模板:

  1. await_suspend:用于控制协程的暂停和恢复,通常是一个异步操作。

  2. await_resume:用于获取 co_await 表达式的结果或者执行特定的操作。

  3. await_ready(可选):用于确定 co_await 表达式是否可以立即执行,通常返回一个 bool 值。

co_await std::suspend_always{} 属于一种特殊情况,用于在协程中立即暂停执行,并且没有实际的异步操作。这是 C++ 标准库中提供的一种符合 awaitable 概念的对象。std::suspend_always 会始终导致协程暂停,因为其 await_suspend 方法会返回一个总是暂停的状态。

下面是await 和resum的一个简单例子


#include <coroutine>
#include <iostream>
#include <stdexcept>
#include <thread>
 
struct awaitable
{
    std::thread* p_out;
    bool await_ready() 
    { 
        printf("ready\n");
        return false; 
    }
    void await_suspend(std::coroutine_handle<> h) // 这个是协程挂起时,要执行的操作
    {
        std::thread& out = *p_out;
        if (out.joinable())
            throw std::runtime_error("thread 输出参数非空"); 
        out = std::thread([h] 
        { 
            sleep(5);
            printf("开始执行唤醒%ld\n", std::this_thread::get_id());
            h.resume();     // !!这里其实就是恢复协程,执行co_await switch_to_new_thread下面的代码
            sleep(2);
            printf("异步线程退出\n");
        });
        printf("新线程id:%ld 当前线程id:%ld\n", out.get_id(), std::this_thread::get_id());
        std::cout << "2新线程 ID:" << out.get_id() << '\n';
    }
    void await_resume() 
    {
        printf("await_resume\n");
    }
};
awaitable switch_to_new_thread(std::thread& out)
{
   
    printf("切换线程\n");
    return awaitable{&out};
}
 
struct task
{
    struct promise_type
    {
        promise_type()
        {
            printf("promise_type构造函数\n");
        }
        task get_return_object() 
        { 
            printf("get_return_object\n");
            return {}; 
        }
        std::suspend_never initial_suspend() 
        { 
            printf("initial_suspend\n");
            return {}; 
        }
        std::suspend_never final_suspend() noexcept 
        { 
            printf("final_suspend\n");
            return {}; 
        }
        void return_void() 
        {
            printf("return_void\n");
        }
        void unhandled_exception() 
        {
            printf("unhandled_exception\n");
        }
    };
};
 
task resuming_on_new_thread(std::thread& out)
{
 
    printf("进入到了resuming_on_new_thread\n");
    std::cout << "协程开始,线程 ID:" << std::this_thread::get_id() << '\n';
    co_await switch_to_new_thread(out);
    std::cout << "协程恢复,线程 ID:" << std::this_thread::get_id() << '\n';
 
}
 
int main()
{
    std::thread out;
    resuming_on_new_thread(out);
    std::cout << "!!这里是同步立马执行,协程只会恢复到resuming_on_new_thread函数" << std::this_thread::get_id() << '\n';
    out.join(); // 等待新线程完成
}

suspend_never  指示编译器永远不要挂起协程,在 co_await 处立即继续执行。

suspend_always: 指示编译器总是挂起协程,在 co_await 处暂停协程执行,等待后续的异步操作完成后再恢复执行。

  • co_yield 表达式——用于暂停执行并返回一个值:
  • co_return 语句——用于完成执行并返回一个值:
    
    #include <coroutine>
    #include <iostream>
    #include <stdexcept>
    #include <thread>
     #include <coroutine>
    #include <iostream>
    #include <vector>
    
    // 定义 generator 类型,用于协程逐步生成值
    struct generator
    {
        struct promise_type
        {
            int value;
            std::coroutine_handle<> continuation;
    
            generator get_return_object() 
            { 
                return { std::coroutine_handle<promise_type>::from_promise(*this) }; 
            }
            std::suspend_always initial_suspend() 
            { 
                continuation = std::coroutine_handle<promise_type>::from_promise(*this);
                return {}; 
            }
            std::suspend_always final_suspend() noexcept 
            { 
                return {}; 
            }
            void return_void() 
            {
            }
            void unhandled_exception() 
            {
                std::terminate();
            }
            auto yield_value(int v) 
            {
                value = v;
                // continuation.resume();
                return std::suspend_always{};
            }
        };
    
        std::coroutine_handle<promise_type> coro_handle;
    
        generator(std::coroutine_handle<promise_type> h) : coro_handle(h) {}
        ~generator() { coro_handle.destroy(); }
        bool next()
        {
            if (coro_handle)
            {
                coro_handle.resume();
                return !coro_handle.done();
            }
            return false;
        }
        int current_value() const
        {
            return coro_handle.promise().value;
        }
    };
    
    generator example_generator()
    {
        for (int i = 0; i < 5; ++i)
        {
            co_yield i; // 逐个生成值
        }
    }
    
    int main()
    {
        auto gen = example_generator();
        while (gen.next())
        {
            std::cout << "生成的值是:" << gen.current_value() << '\n';
        }
        return 0;
    }
    

#include <coroutine>
#include <cstdint>
#include <exception>
#include <iostream>
 
template<typename T>
struct Generator
{
    // 类名 'Generator' 只是我们的选择,使用协程魔法不依赖它。
    // 编译器通过关键词 'co_yield' 的存在识别协程。
    // 你可以使用 'MyGenerator'(或者任何别的名字)作为替代,只要在类中包括了
    // 拥有 'MyGenerator get_return_object()' 方法的嵌套 struct promise_type。
    // (注意:在重命名时,你还需要调整构造函数/析构函数的声明。)
 
    struct promise_type;
    using handle_type = std::coroutine_handle<promise_type>;
 
    struct promise_type // 必要
    {
        T value_;
        std::exception_ptr exception_;
 
        Generator get_return_object()
        {
            return Generator(handle_type::from_promise(*this));
        }
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void unhandled_exception() { exception_ = std::current_exception(); } // 保存异常
 
        template<typename From>   
        std::suspend_always yield_value(From&& from)
        {
            value_ = std::forward<From>(from); // 在承诺中缓存结果
            return {};
        }
        void return_void() {}
    };
 
    handle_type h_;
 
    Generator(handle_type h) : h_(h) {}
    ~Generator() { h_.destroy(); }
    explicit operator bool()
    {
        fill(); // 获知协程是结束了还是仍能通过 C++ getter(下文的 operator())
                // 获得下一个生成值的唯一可靠方式,是执行/恢复协程到下一个 co_yield 节点
                // (或让执行流抵达结尾)。
                // 我们在承诺中存储/缓存了执行结果,使得 getter(下文的 operator())
                // 可以获得这一结果而不执行协程。
        return !h_.done();
    }
    T operator()()
    {
        fill();
        full_ = false;// 我们将移动走先前缓存的结果来重新置空承诺
        return std::move(h_.promise().value_);
    }
 
private:
    bool full_ = false;
 
    void fill()
    {
        if (!full_)
        {
            h_();
            if (h_.promise().exception_)
                std::rethrow_exception(h_.promise().exception_);
            // 在调用上下文中传播协程异常
 
            full_ = true;
        }
    }
};
 
Generator<uint64_t>
fibonacci_sequence(unsigned n)
{
    if (n == 0)
        co_return;
 
    if (n > 94)
        throw std::runtime_error("斐波那契序列过大,元素将会溢出。");
 
    co_yield 0;
 
    if (n == 1)
        co_return;
 
    co_yield 1;
 
    if (n == 2)
        co_return;
 
    uint64_t a = 0;
    uint64_t b = 1;
 
    for (unsigned i = 2; i < n; i++)
    {
        uint64_t s = a + b;
        co_yield s;
        a = b;
        b = s;
    }
}
 
int main()
{
    try
    {
        auto gen = fibonacci_sequence(10); // 最大值94,避免 uint64_t 溢出
 
        for (int j = 0; gen; j++)
            std::cout << "fib(" << j << ")=" << gen() << '\n';
    }
    catch (const std::exception& ex)
    {
        std::cerr << "发生了异常:" << ex.what() << '\n';
    }
    catch (...)
    {
        std::cerr << "未知异常。\n";
    }
}

set(CMAKE_CXX_FLAGS "-std=c++20 -fcoroutines")

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值