在C++20引入标准协程之后,开发者可以基于协程特性实现轻量级的并发逻辑,而协程调度器是管理协程生命周期、控制协程执行顺序的核心组件。一个简单的协程调度器需要实现协程的注册、挂起、恢复以及调度队列管理等功能,下面我们逐步讲解实现过程。

核心概念铺垫
实现协程调度器前需要先明确几个核心概念:
- 协程句柄:C++20中
std::coroutine_handle<>用于操作协程的状态,可控制协程的恢复和销毁。 - 协程承诺类型:每个协程都有一个承诺类型,用于定义协程的初始行为、最终行为以及返回值处理逻辑。
- 调度队列:用于存储待执行的协程,调度器从队列中取出协程执行。
协程承诺类型定义
首先定义调度器对应的协程承诺类型,需要适配协程的基本行为:
#include <coroutine>
#include <queue>
#include <iostream>
#include <memory>
// 前向声明调度器类
class CoroutineScheduler;
// 协程承诺类型
struct TaskPromise {
// 协程返回的Task类型前向声明
struct Task;
// 协程开始时直接挂起,等待调度器调度
std::suspend_always initial_suspend() { return {}; }
// 协程结束时挂起,等待调度器处理后续逻辑
std::suspend_always final_suspend() noexcept { return {}; }
// 返回协程对应的Task对象
Task get_return_object();
// 协程中没有co_return时的处理
void return_void() {}
// 协程抛出异常时的处理
void unhandled_exception() { std::terminate(); }
// 用于让协程主动让出执行权,挂起并加入调度队列
struct Awaitable {
CoroutineScheduler* scheduler;
bool await_ready() const noexcept { return false; }
void await_suspend(std::coroutine_handle<TaskPromise> h) noexcept;
void await_resume() noexcept {}
};
// 获取让出执行权的等待器
Awaitable yield_value(CoroutineScheduler* s) noexcept {
return Awaitable{s};
}
};
调度器实现
调度器需要维护一个协程队列,提供协程的入队、执行、调度等能力:
class CoroutineScheduler {
private:
// 存储待执行的协程句柄
std::queue<std::coroutine_handle<>> ready_queue;
public:
// 将协程加入调度队列
void schedule(std::coroutine_handle<> h) {
ready_queue.push(h);
}
// 执行所有待调度的协程,直到队列为空
void run() {
while (!ready_queue.empty()) {
auto h = ready_queue.front();
ready_queue.pop();
// 恢复协程执行
if (h && !h.done()) {
h.resume();
}
}
}
// 判断调度队列是否为空
bool is_empty() const {
return ready_queue.empty();
}
};
// 实现Awaitable的await_suspend逻辑,将协程加入调度器队列
void TaskPromise::Awaitable::await_suspend(std::coroutine_handle<TaskPromise> h) noexcept {
scheduler->schedule(h);
}
Task类型封装
封装一个Task类型,方便用户创建协程并与调度器交互:
struct TaskPromise::Task {
using promise_type = TaskPromise;
std::coroutine_handle<TaskPromise> handle;
// 构造函数,保存协程句柄
Task(std::coroutine_handle<TaskPromise> h) : handle(h) {}
// 析构时销毁协程
~Task() {
if (handle) {
handle.destroy();
}
}
// 禁止拷贝,允许移动
Task(const Task&) = delete;
Task& operator=(const Task&) = delete;
Task(Task&& other) noexcept : handle(other.handle) {
other.handle = nullptr;
}
Task& operator=(Task&& other) noexcept {
if (this != &other) {
if (handle) handle.destroy();
handle = other.handle;
other.handle = nullptr;
}
return *this;
}
// 启动协程,将其加入调度器
void start(CoroutineScheduler& scheduler) {
// 初始挂起后,将协程加入调度队列
scheduler.schedule(handle);
}
};
// 实现get_return_object,返回Task对象
TaskPromise::Task TaskPromise::get_return_object() {
return Task{std::coroutine_handle<TaskPromise>::from_promise(*this)};
}
使用示例
下面编写一个简单的测试示例,验证调度器的功能:
// 定义一个协程函数,接收调度器指针,可主动让出执行权
TaskPromise::Task test_coroutine(CoroutineScheduler* scheduler, int id) {
std::cout << "协程" << id << "开始执行" << std::endl;
// 主动让出执行权,挂起并加入调度队列
co_await scheduler;
std::cout << "协程" << id << "恢复执行" << std::endl;
co_await scheduler;
std::cout << "协程" << id << "执行结束" << std::endl;
}
int main() {
CoroutineScheduler scheduler;
// 创建三个协程任务
auto task1 = test_coroutine(&scheduler, 1);
auto task2 = test_coroutine(&scheduler, 2);
auto task3 = test_coroutine(&scheduler, 3);
// 启动所有协程
task1.start(scheduler);
task2.start(scheduler);
task3.start(scheduler);
// 运行调度器
std::cout << "调度器开始运行" << std::endl;
scheduler.run();
std::cout << "调度器运行结束" << std::endl;
return 0;
}
代码逻辑说明
上述示例中,三个协程创建后初始处于挂起状态,调用start方法后加入调度器的就绪队列。调度器run方法会依次取出队列中的协程执行,协程执行到co_await scheduler时,会主动挂起并将自身重新加入调度队列,等待下一次调度。最终输出会交替显示三个协程的执行过程,体现了调度器对协程执行顺序的控制能力。
这个简单的调度器实现了基础的协程调度功能,实际生产环境中可以根据需求扩展优先级队列、定时调度、多线程调度等能力,满足更复杂的业务场景需求。
coroutine_schedulerC++协程调度协程实现修改时间:2026-06-29 09:54:39