1. 项目背景与核心挑战
在异步任务调度系统中,如何准确感知任务完成状态并触发后续操作是个经典难题。GlobalExecutor作为全局任务调度器,其notify_task_finished机制相当于系统的心跳检测器——它需要在不阻塞主线程的前提下,实时感知所有子任务的消亡时刻。这个看似简单的状态同步问题,实际涉及三个维度的技术博弈:
- 性能维度:原子操作 vs 锁竞争
- 准确性维度:虚假唤醒 vs 信号丢失
- 资源维度:忙等待 vs 条件阻塞
我们最终选择的原子递减+条件变量方案,本质上是在这三个维度上寻找最优解。就像交通信号灯系统,既需要快速响应车辆通过(原子操作保证性能),又要在红灯时确保所有车辆真正停下(条件变量保证准确性)。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术方案深度解析
2.1 原子计数器:无锁化的基石
cpp复制std::atomic<int> active_tasks_{0};
void notify_task_finished() {
if (active_tasks_.fetch_sub(1, std::memory_order_release) == 1) {
std::lock_guard<std::mutex> lk(mutex_);
cond_.notify_all();
}
}
这里的内存序选择release而非seq_cst是个关键优化点。在x86体系下两者性能差异可能不明显,但在ARM等弱内存模型架构上,release能减少约30%的指令开销。就像快递柜取件——我们只需要确保包裹放入后其他人能立即看到(release语义),而不需要全局暂停所有快递柜操作(seq_cst的开销)。
踩坑记录:早期版本使用
memory_order_relaxed导致偶发的条件变量唤醒丢失。这是因为task counter的修改与条件变量操作之间缺乏happens-before关系。
2.2 条件变量:精准唤醒的艺术
条件变量的使用遵循"三明治"模式:
cpp复制// 等待侧
std::unique_lock<std::mutex> lk(mutex_);
cond_.wait(lk, [this]{ re
