能否用C++无栈协程替换模拟器栈式Fiber?求低侵入改造方案
栈式Fiber转C++无栈协程的低侵入改造建议请求
我正考虑将一款使用栈式Fiber(stackful)的旧模拟器代码替换为C++无栈协程(stackless)。我认为无法完全不破坏现有依赖,但希望尽可能保留原有机制。
现有fiber类定义
struct fiber{ fiber(const fiber&) = delete; fiber(scheduler& scheduler, std::function<void()> call_back, size_t stack_size = 4096); ~fiber(); void suspend(); void resume(); void finish(); void execute(); void wait(event&); void wait(sim_time_t = 0); static auto get_current() -> fiber*; private: scheduler& _scheduler; std::function<void()> _call_back; bool _finished{false}; void* _win_fiber; };
关键函数实现
fiber* fiber::get_current() { return (fiber*)GetFiberData(); } void fiber::suspend() { // call from this fiber ::SwitchToFiber(_scheduler._main_fiber); } void fiber::resume() { // call from main fiber ::SwitchToFiber(_win_fiber); }
核心逻辑说明:
get_current():用于确定当前运行的fiber实例suspend():从当前fiber切回调度器主执行流resume():从调度器主执行流恢复挂起的fiber
低侵入改造方案建议
1. 保留fiber类对外接口,内部替换为协程实现
- 完全保留原有
fiber类的公共方法签名,不改动外部依赖代码的调用逻辑 - 移除
_win_fiber成员,替换为C++协程句柄std::coroutine_handle<> - 用**线程局部存储(TLS)**替代
GetFiberData()实现get_current(),比如新增static thread_local fiber* _current_fiber,在协程启动时赋值、结束时清空
2. 适配suspend()与resume()逻辑
suspend():不再调用SwitchToFiber,而是触发协程挂起,同时将当前fiber实例交还给调度器管理。需要自定义协程promise类型,让挂起动作通知调度器将该fiber移入等待队列resume():通过协程句柄调用resume()方法恢复执行,替代原有的SwitchToFiber切换逻辑
3. 改造wait系列方法
- 对于
wait(event&):将原阻塞等待逻辑改为协程挂起,注册事件回调,当事件触发时由调度器将该fiber重新加入就绪队列并恢复执行 - 对于
wait(sim_time_t):将fiber加入调度器的延时队列,到达指定时间后由调度器唤醒恢复
4. 调度器的最小调整
- 原调度器的fiber切换逻辑改为协程句柄队列管理:维护就绪队列、等待队列、延时队列,循环处理就绪队列中的协程,直到所有任务完成
示例代码片段(核心改造部分)
#include <coroutine> #include <thread> struct fiber{ // 保留原有公共接口... private: scheduler& _scheduler; std::function<void()> _call_back; bool _finished{false}; std::coroutine_handle<> _coro_handle; // 替换原_win_fiber static thread_local fiber* _current_fiber; // TLS存储当前fiber }; // get_current()改造实现 fiber* fiber::get_current() { return _current_fiber; } // suspend()改造逻辑示例 void fiber::suspend() { _current_fiber = nullptr; _coro_handle.suspend(); _current_fiber = this; // 恢复执行时重新设置当前fiber } // resume()改造逻辑示例 void fiber::resume() { _current_fiber = this; _coro_handle.resume(); }
内容的提问来源于stack exchange,提问作者Gene
相关产品推荐
相关产品推荐

