基于Boost ASIO实现条件变量:io_context/strand使用问题排查
一、断言失败的根本原因
你遇到的total_mem >= mem_used_断言失败,核心问题出在原strand关联的io_context被其他线程驱动执行。strand本身不具备任务队列的独立性,它只是绑定到某个io_context上的串行执行调度器——如果这个io_context在程序其他地方被调用了run()/run_one(),哪怕你没主动调用try_run_one(),strand上post的任务也会被触发执行。这种提前执行会打乱MemoryChecker的内存申请/释放顺序,导致mem_used_的计数逻辑被破坏,最终触发断言。
换成独立的io_context(即你的pending_queue_)后,只要这个io_context的run()/try_run_one()完全由你的代码控制,任务就只会在你预期的时机执行,内存计数逻辑就能正常工作。
二、io_context是否能保证FIFO执行顺序
可以明确:单个Boost ASIO io_context的post操作严格保证FIFO顺序。io_context内部维护的是线程安全的FIFO任务队列,无论从哪个线程post任务,任务都会按照提交的先后顺序被执行——前提是你没有用strand以外的调度器打乱顺序,且所有任务都通过同一个io_context驱动执行。
所以你替换后的方案是可靠的,只要确保这个pending_queue_的io_context没有被其他代码意外调用run方法,就能保证任务串行按序执行。
三、替代实现方案
方案1:强化独立io_context的独占性
- 确保
pending_queue_是完全独立的io_context,不与程序中其他io_context共享线程或执行逻辑。 - 封装
async_pending_queue时,只暴露触发任务执行的接口(比如自定义的trigger_one()内部调用try_run_one()),避免外部直接操作io_context的run方法。
方案2:改用Boost ASIO原生的协程友好条件变量
如果你需要的是协程风格的条件等待,Boost ASIO从1.78版本开始提供了asio::condition_variable,支持协程awaitable接口,无需自己实现队列:
asio::condition_variable cv; asio::mutex mutex; bool ready = false; // 协程中等待条件 co_await cv.async_wait(mutex, [&](){ return ready; }, asio::use_awaitable); // 其他地方通知条件满足 { std::lock_guard<asio::mutex> lock(mutex); ready = true; } cv.notify_one();
这个原生实现更简洁,且天然适配Boost ASIO的异步模型,避免自己实现队列时的潜在问题。
方案3:基于strand的修正方案
如果一定要用strand,需要确保strand绑定的io_context完全由你控制:
- 创建专属的io_context给strand使用,不要让其他代码调用这个io_context的run方法。
- 仅在需要触发任务时,调用该io_context的
try_run_one()或run_for()等方法,确保任务执行时机可控。
内容的提问来源于stack exchange,提问作者Suraaj K S

