基于C++20实现一个简单的协程库

1 阅读13分钟

前言

要理解C++20的协程怎么用,得先理解关键字,三个关键字:co_awaitco_yieldco_return,所有函数体内有这三个关键字其中一个或以上的,都将被转换成协程函数。还有两个概念:awaitergenerator,awaiter是co_await作用的对象,而generator是管理协程句柄(std::coroutine_handle)的对象,也是协程函数的返回值。

另外,C++20的协程是缺少“调度器”的,需要自行实现协程的调度

注意点:下面我会说“协程”和“协程函数”,注意两者区别

C++20协程关键字

co_return [result]

result是协程的最终返回结果,没有result时即无返回

co_yield value

co_yield会将协程挂起,value是协程挂起时返回的值,不可省略,且必须与co_return同类型,当co_return无返回值时,不可使用co_yield,每次执行到co_yield都可以获取一次协程的返回值(即多次返回值)

co_await value

①value是一个“awaiter”对象,不可省略。

②co_await可重载,也是一个“运算符函数”,重载的co_await运算符函数必须返回一个awaiter。

awaiter说明

awaiter是co_await直接作用的对象,它决定了co_await操作时协程如何响应

awaiter类型必须拥有以下三个接口函数:

await_ready

co_await接收到awaiter参数时首先执行的函数,返回值bool。当返回值为false时,协程将被挂起,然后执行await_suspend函数;当返回值为true时,协程不会挂起而继续执行,将跳过await_suspend函数。

await_suspend

await_suspend返回类型有三种:

①bool,如果返回false,则立即恢复协程而不挂起。如果返回true,协程挂起。

②void,视为返回true

③std::coroutine_handle<>,挂起当前协程,并立即恢复返回的另一个协程,就是该重要的机制,支撑起协程的嵌套和转移

关于await_suspend的实参——协程的句柄,可以是默认的std::coroutine_handle<>,也可以是指定的std::coroutine_handle<promise_type>,视功能需求自定义。

await_resume

await_resume函数的返回值就是co_await运算符的返回值。当协程在co_await挂起后被恢复时,或者协程在await_ready返回true时,将会调用await_resume。

其中,标准库提供了两个内置的awaiter,分别是std::suspend_always和std::suspend_never

promise_type说明

promise_type是协程内部状态的控制核心,控制着协程的创建、挂起、恢复和销毁,它还负责协程的最终返回(或异常)以及协程返回值的传递。

promise_type类型的接口函数如下表:

函数描述函数说明
generator get_return_object()在协程执行前调用,用于构造generator对象,然后将存放了promise_type引用的协程句柄传送到generator对象中存放。该接口的返回值就是协程函数的直接返回值
awaiter initial_suspend()在协程初始化时调用,返回一个awaiter对象
awaiter final_suspend() noexcept(true)在协程结束时调用。必须有noexcept修饰
awaiter yield_value(type value)co_yield操作时调用,value即是co_yield的参数。【无co_yield时非必须】
void unhandled_exception()协程发生异常时调用
void return_void()当co_return执行且无返回值时调用。有该函数的时候不能存在return_value函数。【co_return有返回值时非必须】
void return_value(type value)当co_return执行且有返回值时调用,value即是co_return的参数。有该函数的时候不能存在return_void函数。【co_return无返回值时非必须】
static generator get_return_object_on_allocation_failure()当标识为noexcept的内存分配函数返回nullptr时,协程函数在返回generator时将会通过调用此接口获得返回值。【非必须】

generator说明

generator是管理协程句柄(std::coroutine_handle)的对象,也是协程函数的返回值,一般由generator对象来操作promise_type对象

generator的对象由promise_type的get_return_object函数生成并返回

协程库实现

理解了上面的各个要点后,就能着手实现一个简单的协程库了。

以下就是源码,支持协程嵌套和转移,也支持异步执行及完成后唤醒,但是线程池、事件队列需要自行实现

#ifndef CO_TASK_H
#define CO_TASK_H#include <coroutine>
#include <functional>  // std::function
#include <memory>  // std::shared_ptr  std::make_shared// 用于在协程结束时自动恢复续体的 Awaitable
template<typename _Tp>
struct FinalAwaitable 
{
    bool await_ready() const noexcept 
    { return false; }
    
    // 对 C++20 对话式对称传输的支持:返回 handle 会立即切换到该协程
    std::coroutine_handle<> await_suspend(std::coroutine_handle<_Tp> h) noexcept 
    {
        // 这里的 h 是当前结束的协程(子协程)
        if constexpr (std::is_same<_Tp, void>::value)
        { return std::noop_coroutine(); }
        else 
        {
            auto& promise = h.promise(); 
            if (promise.continuation) 
            { return promise.continuation; }
            return std::noop_coroutine();
        }
    }
    
    void await_resume() noexcept 
    {}
};
​
template<typename _Ret, typename _ThreadPoolEnqueue, typename _EventLoopEnqueue>
struct ThreadPoolAwaiter 
{
    _ThreadPoolEnqueue pool_enqueue;
    _EventLoopEnqueue loop_enqueue;
    std::function<_Ret()> func;
    _Ret result;
​
    ThreadPoolAwaiter(_ThreadPoolEnqueue &&p, _EventLoopEnqueue &&l, std::function<_Ret()> &&f)
     : pool_enqueue(std::move(p))
     , loop_enqueue(std::move(l))
     , func(std::move(f)) 
    {}
​
    // 永远挂起,以便将任务切走
    bool await_ready() const noexcept 
    { return false; }
​
    void await_suspend(std::coroutine_handle<> handle) 
    {
        // 1. 将任务提交给线程池
        pool_enqueue([this, handle]() mutable {
            try 
            {
                if constexpr (!std::is_void_v<_Ret>) 
                {
                    result = func();
                } 
                else 
                {
                    func();
                }
            } 
            catch (...) 
            {
                // 异常处理逻辑可以根据需求扩展
            }
​
            // 2. 线程池任务完成后,将“恢复协程”的操作投递回主事件循环
            loop_enqueue([handle]() {
                handle.resume();
            });
        });
    }
​
    _Ret await_resume() 
    { return std::move(result); }
};
​
template<typename _Tp>
struct Task 
{
public:
    struct promise_type;
    using co_handle = std::coroutine_handle<promise_type>;
​
    using value_type = _Tp;
    using reference = _Tp &;
    using rvalue_reference = _Tp &&;
    using const_reference = const _Tp &;
​
    struct promise_type 
    {
        value_type value;
        std::exception_ptr exception;
        std::coroutine_handle<> continuation; // 父协程的句柄
​
        Task get_return_object() 
        { return Task(co_handle::from_promise(*this)); }
​
        std::suspend_always initial_suspend() 
        { return {}; }
​
        FinalAwaitable<promise_type> final_suspend() noexcept 
        { return {}; }
​
        void return_value(rvalue_reference v) 
        { value = std::move(v); }
​
        void return_value(const_reference v) 
        { value = v; }
​
        std::suspend_always yield_value(rvalue_reference v) 
        { 
            value = std::move(v); 
            return {}; 
        }
​
        std::suspend_always yield_value(const_reference v) 
        { 
            value = v; 
            return {}; 
        }
​
        void unhandled_exception() 
        { exception = std::current_exception(); }
    };
​
public:
    Task(co_handle h)
     : _M_handle(new co_handle(h), _S_on_release) 
    { }
​
    // 是否已执行完毕
    operator bool() const noexcept 
    { return _M_handle && *_M_handle && _M_handle->done(); }
​
    void operator()()
    {
        if(_M_handle && *_M_handle)
        { _M_handle->resume();  }
    }
​
    // 获取返回值
    reference operator*() noexcept 
    { return _M_handle->promise().value; }
​
    auto operator co_await() noexcept 
    {
        struct Awaiter 
        {
            co_handle callee;
​
            bool await_ready() const noexcept 
            { return !callee || callee.done(); }
​
            // h 是当前正在 co_await 的父协程句柄
            std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) noexcept 
            {
                callee.promise().continuation = h; // 绑定续体
                return callee; // 对称传输:切换到子协程执行
            }
​
            value_type await_resume() 
            {
                if (callee.promise().exception) 
                { std::rethrow_exception(callee.promise().exception); }
                return std::move(callee.promise().value);
            }
        };
        return Awaiter{*_M_handle};
    }
​
private:
    static void _S_on_release(co_handle *h)
    {
        h->destroy();
        delete h;
    }
​
private:
    std::shared_ptr<co_handle> _M_handle;
};
​
// 针对 void 的特化
template<>
struct Task<void> 
{
public:
    struct promise_type;
    using co_handle = std::coroutine_handle<promise_type>;
​
    struct promise_type 
    {
        std::exception_ptr exception;
        std::coroutine_handle<> continuation; // 父协程的句柄
​
        Task get_return_object() 
        { return Task(co_handle::from_promise(*this)); }
​
        std::suspend_always initial_suspend() 
        { return {}; }
​
        FinalAwaitable<promise_type> final_suspend() noexcept 
        { return {}; }
​
        void return_void() 
        {}
​
        std::suspend_always yield_void() 
        { return {}; }
​
        void unhandled_exception() 
        { exception = std::current_exception(); }
    };
​
    Task(co_handle h)
     : _M_handle(new co_handle(h), _S_on_release) 
    { }
​
    // 是否已执行完毕
    operator bool() const noexcept
    { return _M_handle && *_M_handle && _M_handle->done(); }
​
    void operator()()
    {
        if(_M_handle && *_M_handle)
        { _M_handle->resume(); }
    }
​
    // 获取返回值
    void operator*() const noexcept 
    { }
​
    auto operator co_await() noexcept 
    {
        struct Awaiter 
        {
            co_handle callee;
​
            bool await_ready() const noexcept 
            { return !callee || callee.done(); }
​
            // h 是当前正在 co_await 的父协程句柄
            std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) noexcept 
            {
                callee.promise().continuation = h; // 绑定续体
                return callee; // 对称传输:切换到子协程执行
            }
​
            void await_resume() 
            {
                if (callee.promise().exception) 
                { std::rethrow_exception(callee.promise().exception); }
            }
        };
        return Awaiter{*_M_handle};
    }
​
private:
    static void _S_on_release(co_handle *h)
    {
        h->destroy();
        delete h;
    }
​
private:
    std::shared_ptr<co_handle> _M_handle;
​
};
​
/**
 * 在线程池pool中异步执行一个函数,得到结果后在loop中唤醒协程
 * @param pool  线程池的提交函数,接收一个 std::function<void()> 参数
 * @param loop  事件循环的提交函数,接收一个 std::function<void()> 参数
 * @param f  需要在线程池中异步执行的函数,返回值将被协程获取,在loop中继续执行co_await返回后的操作
 */
template<typename _ThreadPoolEnqueue, typename _EventLoopEnqueue, typename _Func>
auto AsyncExec(_ThreadPoolEnqueue &&pool, _EventLoopEnqueue &&loop, _Func &&f) 
{
    using Ret = std::invoke_result_t<_Func>;
    return ThreadPoolAwaiter<Ret, _ThreadPoolEnqueue, _EventLoopEnqueue>(std::move(pool), std::move(loop), std::move(f));
}
​
#endif // CO_TASK_H

使用例子

1.事件队列的实现

文件名:event_queue.h

#ifndef EVENT_QUEUE_H
#define EVENT_QUEUE_H#include <atomic>  // std::atomic_flag
#include <queue>  // std::queue
#include <functional>  // std::function
#include <thread>  //  std::this_thread::yieldtemplate<typename _Tp>
class EventQueue
{
public:
    using EventWrapper = std::function<_Tp()>;
​
public:
    void Push(EventWrapper &&e)
    {
        _M_Lock();
        _M_event_queue.push(std::move(e));
        _M_Unlock();
    }
​
    EventWrapper Pop()
    {
        EventWrapper result;
        _M_Lock();
        if(_M_event_queue.empty())
        {
            _M_Unlock();
            return result;
        }
        EventWrapper e = std::move(_M_event_queue.front());
        _M_event_queue.pop();
        _M_Unlock();
        result.swap(e);
        return result;
    }
​
private:
    void _M_Lock() noexcept
    {
        while(_M_lock.test_and_set())
        { std::this_thread::yield(); }
    }
​
    void _M_Unlock() noexcept
    { _M_lock.clear(); }
​
private:
    std::atomic_flag _M_lock;
    std::queue<EventWrapper> _M_event_queue;
};
​
#endif // EVENT_QUEUE_H

2.事件循环的实现

文件名:event_loop.h

#ifndef EVENT_LOOP_H
#define EVENT_LOOP_H/**
 * 事件循环类
 */
#include "event_queue.h"#include <thread>  // std::this_thread::sleep_for
#include <chrono>  // std::chrono::milliseconds
#include <functional>  // std::function
#include <future>  // std::future  std::future_status
#include <atomic>  // std::atomic_boolclass EventLoop
{
public:
    using EventCallback = std::function<void()>;
​
    template<std::size_t _EmptySleep = 10, std::size_t _NormalSleep = 1>
    void Run()
    {
        _M_flag.store(true, std::memory_order_release);
        while(_M_flag.load(std::memory_order_acquire))
        {
            typename EventQueue<void>::EventWrapper f = _M_event_queue.Pop();
            if(!f)
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(_EmptySleep));
                continue;
            }
​
            f();
            std::this_thread::sleep_for(std::chrono::milliseconds(_NormalSleep));
        }
    }
​
    void Enqueue(EventCallback &&e)
    { _M_event_queue.Push(std::move(e)); }
​
    void Stop() noexcept
    { _M_flag.store(false, std::memory_order_release); }
​
private:
    std::atomic_bool _M_flag;
    EventQueue<void> _M_event_queue;
};
​
#endif // EVENT_LOOP_H

3.线程池的实现

#ifndef THREAD_POOL_H
#define THREAD_POOL_H#include <future>  // std::future
#include <atomic>  // std::atomic_flag  std::atomic_bool
#include <queue>  // std::queue
#include <functional>  // std::function
#include <thread>  // std::this_thread::sleep_for  std::this_thread::yield
#include <vector>  // std::vector
#include <memory>  // std::shared_ptr  std::make_sharednamespace detail
{
​
template<typename _AtomicFlag = std::atomic_flag>
class SpinLock
{
public:
    SpinLock()
     : _M_lock(ATOMIC_FLAG_INIT) 
    {}
​
    void lock() noexcept
    {
        while(_M_lock.test_and_set())
        { std::this_thread::yield(); }
    }
​
    void unlock() noexcept
    { _M_lock.clear(std::memory_order_release); }
​
private:    
    std::atomic_flag _M_lock;
};
​
} // namespace detailtemplate<typename _Lock = detail::SpinLock<>>
class ThreadPool
{
private:
    using AsyncTaskWrapper = std::function<void()>;
​
public:
    ThreadPool(std::size_t num_threads = 1)
    {
        _M_flag.store(true, std::memory_order_release);
        while(num_threads-- > 0)
        {
            _M_threads.emplace_back(std::async(std::launch::async, [this](){
                _M_MainLoop();
            }));
        }
    }
    ~ThreadPool()
    {
        Stop();
        for(auto &t : _M_threads)
        { t.get(); }
    }
​
    // 异步执行,不关心结果
    void Async(std::function<void()> &&async_task)
    {
        _M_Lock();
        _M_async_task_queue.push(std::move(async_task));
        _M_Unlock();
    }
​
    void Stop() noexcept
    { _M_flag.store(false, std::memory_order_release); }
​
private:
    void _M_MainLoop()
    {
        while(_M_flag.load(std::memory_order_acquire))
        {
            _M_Lock();
​
            if(_M_async_task_queue.empty())
            {
                _M_Unlock();
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
                continue;
            }
​
            AsyncTaskWrapper task = std::move(_M_async_task_queue.front());
            _M_async_task_queue.pop();
            _M_Unlock();
​
            task();
        }
    }
​
    void _M_Lock() noexcept
    { _M_lock.lock(); }
​
    void _M_Unlock() noexcept
    { _M_lock.unlock(); }
​
private:
    std::queue<AsyncTaskWrapper> _M_async_task_queue;
    _Lock _M_lock;
    std::atomic_bool _M_flag;
    std::vector<std::future<void>> _M_threads;
};
​
#endif // THREAD_POOL_H

4.测试案例

①多线程下的测试案例

#ifdef _WIN32
#include <cstdlib>  // system
#endif 
#include <iostream>  // std::cout
#include <format>  // std::format
#include "thread_pool.h"
#include "event_loop.h"
#include "co_task.h"static EventLoop Main;
static ThreadPool<> Pool(2);
​
// 一个模拟耗时任务
int HeavyComputation(int input) 
{
    std::cout << "[HeavyComputation] caling  thread_ID: " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return input * 2;
}
​
// 协程函数3
Task<double> MyCoroutine3(int id)
{
    std::cout << std::format("[Event Loop---{}---] start coroutine 3 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 1.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 1 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 2.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 2 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 3.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 3 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 4.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 4 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_return 5.5;
}
​
// 协程函数2
Task<int> MyCoroutine2(int id)
{
    std::cout << std::format("[Event Loop---{}---] start coroutine 2 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
​
    auto t3 = MyCoroutine3(id);
    double sum = 0;
    while(!t3)
    {
        double value = co_await AsyncExec(
            std::bind(&ThreadPool<>::Async, &Pool, std::placeholders::_1), 
            std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
            [t3]() mutable {
                t3();
                return *t3;
            }
        );
        sum += value;
    }
    std::cout << std::format("[Event Loop---{}---] coroutine 3 result: {}", id, sum) << std::endl;
    int result = co_await AsyncExec(
        std::bind(&ThreadPool<>::Async, &Pool, std::placeholders::_1), 
        std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
        []() {
            return HeavyComputation(20);
        }
    );
    std::cout << std::format("[Event Loop---{}---] get coroutine 2 result: {}", id, result) << std::endl;
    co_return result;
}
​
// 协程函数
Task<void> MyCoroutine(int id) 
{
    std::cout << std::format("[Event Loop---{}---] start coroutine 1 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    int ret = co_await MyCoroutine2(id);
    std::cout << std::format("[Event Loop---{}---] get coroutine 2 result: {}", id, ret) << std::endl;
    int result = co_await AsyncExec(
        std::bind(&ThreadPool<>::Async, &Pool, std::placeholders::_1), 
        std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
        []() {
            return HeavyComputation(10);
        }
    );
    std::cout << std::format("[Event Loop---{}---] get coroutine 1 result: {} thread_ID: ", id, result) << std::this_thread::get_id() << std::endl;
    Main.Stop(); // 结束后停止循环
}
​
void func()
{
    // 多个多层级的协程
    Task<void> t1 = MyCoroutine(1);
    Task<void> t2 = MyCoroutine(2);
    Main.Enqueue([&t1](){
        t1();
    });
    Main.Enqueue([&t2](){
        t2();
    });
​
    // 运行主循环
    std::cout << "main loop start" << std::endl;
    Main.Run(); 
}
​
int main() 
{
    func();
#ifdef _WIN32
    system("pause");
#endif
    return 0;
}

输出结果(输出打印没加锁会看着有点乱):

main loop start
[Event Loop---1---] start coroutine 1 thread_ID: 1
[Event Loop---1---] start coroutine 2 thread_ID: 1
[Event Loop---1---] start coroutine 3 thread_ID: 2
[Event Loop---2---] start coroutine 1 thread_ID: 1
[Event Loop---2---] start coroutine 2 thread_ID: 1
[Event Loop---2---] start coroutine 3 thread_ID: 3
[Event Loop---1---] coroutine 3 status 1 thread_ID: 3
[Event Loop---2---] coroutine 3 status 1 thread_ID: 2
[Event Loop---1---] coroutine 3 status 2 thread_ID: 2
[Event Loop---2---] coroutine 3 status 2 thread_ID: 2
[Event Loop---1---] coroutine 3 status 3 thread_ID: 2
[Event Loop---2---] coroutine 3 status 3 thread_ID: 2
[Event Loop---1---] coroutine 3 status 4 thread_ID: 2
[Event Loop---2---] coroutine 3 status 4 thread_ID: [Event Loop---1---] coroutine 3 result: 17.5
3
[HeavyComputation] caling  thread_ID: 3
[Event Loop---2---] coroutine 3 result: 17.5
[HeavyComputation] caling  thread_ID: 2
[Event Loop---1---] get coroutine 2 result: 40
[Event Loop---1---] get coroutine 2 result: 40
[HeavyComputation] caling  thread_ID: [Event Loop---2---] get coroutine 2 result: 40
2
[Event Loop---2---] get coroutine 2 result: 40
[HeavyComputation] caling  thread_ID: 3
[Event Loop---1---] get coroutine 1 result: 20 thread_ID: 1

②单线程下事件循环的测试案例

#ifdef _WIN32
#include <cstdlib>  // system
#endif 
#include <iostream>  // std::cout
#include <format>  // std::format
#include "event_loop.h"
#include "co_task.h"static EventLoop Main;
​
// 一个模拟耗时任务
int HeavyComputation(int input) 
{
    std::cout << "[HeavyComputation] caling  thread_ID: " << std::this_thread::get_id() << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return input * 2;
}
​
// 协程函数3
Task<double> MyCoroutine3(int id)
{
    std::cout << std::format("[Event Loop---{}---] start coroutine 3 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 1.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 1 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 2.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 2 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 3.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 3 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_yield 4.5;
    std::cout << std::format("[Event Loop---{}---] coroutine 3 status 4 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    co_return 5.5;
}
​
// 协程函数2
Task<int> MyCoroutine2(int id)
{
    std::cout << std::format("[Event Loop---{}---] start coroutine 2 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
​
    auto t3 = MyCoroutine3(id);
    double sum = 0;
    while(!t3)
    {
        double value = co_await AsyncExec(
            std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
            std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
            [t3]() mutable {
                t3();
                return *t3;
            }
        );
        sum += value;
    }
    std::cout << std::format("[Event Loop---{}---] coroutine 3 result: {}", id, sum) << std::endl;
    int result = co_await AsyncExec(
        std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
        std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
        []() {
            return HeavyComputation(20);
        }
    );
    std::cout << std::format("[Event Loop---{}---] get coroutine 2 result: {}", id, result) << std::endl;
    co_return result;
}
​
// 协程函数
Task<void> MyCoroutine(int id) 
{
    std::cout << std::format("[Event Loop---{}---] start coroutine 1 thread_ID: ", id) << std::this_thread::get_id() << std::endl;
    int ret = co_await MyCoroutine2(id);
    std::cout << std::format("[Event Loop---{}---] get coroutine 2 result: {}", id, ret) << std::endl;
    int result = co_await AsyncExec(
        std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
        std::bind(&EventLoop::Enqueue, &Main, std::placeholders::_1), 
        []() {
            return HeavyComputation(10);
        }
    );
    std::cout << std::format("[Event Loop---{}---] get coroutine 1 result: {} thread_ID: ", id, result) << std::this_thread::get_id() << std::endl;
    Main.Stop(); // 结束后停止循环
}
​
void func()
{
    // 多个多层级的协程
    Task<void> t1 = MyCoroutine(1);
    Task<void> t2 = MyCoroutine(2);
    Main.Enqueue([&t1](){
        t1();
    });
    Main.Enqueue([&t2](){
        t2();
    });
​
    // 运行主循环
    std::cout << "main loop start" << std::endl;
    Main.Run(); 
}
​
int main() 
{
    func();
#ifdef _WIN32
    system("pause");
#endif
    return 0;
}

输出结果:

main loop start
[Event Loop---1---] start coroutine 1 thread_ID: 1
[Event Loop---1---] start coroutine 2 thread_ID: 1
[Event Loop---2---] start coroutine 1 thread_ID: 1
[Event Loop---2---] start coroutine 2 thread_ID: 1
[Event Loop---1---] start coroutine 3 thread_ID: 1
[Event Loop---2---] start coroutine 3 thread_ID: 1
[Event Loop---1---] coroutine 3 status 1 thread_ID: 1
[Event Loop---2---] coroutine 3 status 1 thread_ID: 1
[Event Loop---1---] coroutine 3 status 2 thread_ID: 1
[Event Loop---2---] coroutine 3 status 2 thread_ID: 1
[Event Loop---1---] coroutine 3 status 3 thread_ID: 1
[Event Loop---2---] coroutine 3 status 3 thread_ID: 1
[Event Loop---1---] coroutine 3 status 4 thread_ID: 1
[Event Loop---2---] coroutine 3 status 4 thread_ID: 1
[Event Loop---1---] coroutine 3 result: 17.5
[Event Loop---2---] coroutine 3 result: 17.5
[Thread Pool] caling  thread_ID: 1
[Thread Pool] caling  thread_ID: 1
[Event Loop---1---] get coroutine 2 result: 40
[Event Loop---1---] get coroutine 2 result: 40
[Event Loop---2---] get coroutine 2 result: 40
[Event Loop---2---] get coroutine 2 result: 40
[Thread Pool] caling  thread_ID: 1
[Thread Pool] caling  thread_ID: 1
[Event Loop---1---] get coroutine 1 result: 20 thread_ID: 1