并发原语:如何无忙等待实现仅执行最新触发任务的调度
并发问题无忙等实现方案
核心采用原子状态位+互斥锁+条件变量的组合实现,既规避忙等待,又不会丢失通知,同时天然满足多次触发合并的调度规则。
状态定义
共享三个同步原语:
atomic_bool should_run = false:待执行任务标记,和最初CAS实现语义一致,值为true代表存在待处理的工作请求mutex mtx:配合条件变量使用的互斥锁condition_variable cv:用于线程阻塞/唤醒的条件变量
实现代码
伪代码和原有实现风格保持一致:
// 共享状态初始化 mutex mtx condition_variable cv atomic_bool should_run = false <线程A 触发逻辑> if (需要启动工作) { // 原子方式将标记设为true,返回设置前的旧值 old_state = should_run.exchange(true) // 仅当之前没有待处理任务时才发送唤醒信号,避免冗余系统调用 if (old_state == false) { lock(mtx) cv.notify_one() unlock(mtx) } } <线程B 执行逻辑> loop { lock(mtx) // 阻塞等待直到待执行标记为true,wait内部会自动处理虚假唤醒 cv.wait(mtx, []() { return should_run.load() }) // 拿到执行权后立刻清空标记,开始处理任务 should_run.store(false) unlock(mtx) // 执行任务期间不持有锁,不阻塞线程A发通知 do_work() }
规则匹配验证
- 无忙等:线程B无待处理任务时会完全阻塞在
cv.wait调用上,不占用CPU时间片,不存在轮询开销 - 不丢通知:所有触发请求首先会写入
should_run状态位持久化,即使发送通知时线程B正在执行do_work()、未处于wait阻塞状态,等B完成当前任务回到wait检查点时,会直接检测到标记为true,无需等待新通知就会执行下一轮任务 - 自动合并多次触发:线程B执行任务期间,无论线程A触发多少次通知,
should_run只会保持true状态,不会累计计数,B完成当前任务后仅会执行1次新工作,完全符合“累计N次通知仅执行1次”的要求
实现细节说明
线程A侧仅在should_run从false切到true的时候发送唤醒信号,是因为如果旧值已经为true,说明已经有未处理的任务、唤醒信号已经发送过,重复调用notify_one不会带来任何收益,只会增加不必要的系统调用开销。
另外cv.wait传入谓词判断的写法,会自动处理条件变量常见的虚假唤醒问题,不需要额外加循环判断。
内容的提问来源于stack exchange,提问作者linkedin
相关产品推荐
相关产品推荐

