您的位置:首页 >C++20协程实现状态机教程
发布于2026-03-13 阅读(0)
扫一扫,手机访问
协程状态机的核心是“状态转移控制权”而非“挂起”,需自定义promise_type接管流转逻辑,通过final_suspend返回suspend_always防止销毁、unhandled_exception处理异常、next_state驱动跳转,并由驱动循环显式resume推进状态。

用 C++20 协程写状态机,关键不在 co_await 本身,而在如何把每个状态封装成可恢复的执行片段,并让状态跳转由协程的恢复点(resume point)自然承载。标准库不提供现成的状态机协程框架,必须自己设计 promise_type 来接管状态流转逻辑。
默认的 std::coroutine_handle 无法支撑状态机语义——你不能让协程在状态结束时自动销毁(否则无法做状态迁移),也不能任由异常崩溃掉整个状态流。需要:
final_suspend 返回 std::suspend_always{},防止协程彻底销毁,保留 handle 供外部驱动下个状态unhandled_exception 至少记录或转发异常,避免静默终止(状态机里异常常意味着非法转移)promise_type 中添加 next_state 成员(如 std::function<void()> 或枚举),并在 await_resume() 后主动调用它struct state_machine_promise {
std::function next_state;
auto get_return_object() { return state_machine{this}; }
auto initial_suspend() { return std::suspend_always{}; }
auto final_suspend() noexcept { return std::suspend_always{}; }
void unhandled_exception() { /* 记录异常,不抛出 */ }
void return_void() {}
auto await_transform(auto&&) { return simple_awaiter{*this}; }
}; 每个状态对应一个 co_await 表达式,但它的 awaiter 不该只做“等待”,而应完成三件事:保存当前状态上下文、触发退出逻辑(如清理资源)、设置 next_state。常见错误是把所有状态逻辑塞进一个协程函数里,结果变成难以调试的“大面条”。
state_machine 类型(包装了 coroutine_handle<state_machine_promise>)simple_awaiter::await_ready() 应始终返回 false,确保每次 co_await 都真实挂起,把控制权交还给驱动循环co_yield 实现状态跳转——它语义是“产出值并挂起”,和状态机的“执行→转移”模型不匹配协程状态机没有内置调度器,你得自己写一个运行循环来推进状态。容易忽略的是:不能无条件 handle.resume(),必须先检查 handle.done(),否则对已结束协程 resume 会触发未定义行为(UB)。
void run_state_machine(state_machine sm) {
auto h = sm.handle;
while (!h.done()) {
h.resume();
// 此处可插入日志、超时检查、事件分发等
}
}真正复杂的地方在于状态间的数据传递——promise_type 是唯一共享上下文的位置,所有状态共用同一份 promise 实例,变量生命周期必须严格匹配整个状态机周期,局部变量不能跨 co_await 存活(除非用 static 或堆分配)。
下一篇:车身广告审批流程全解析
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9