关于简单生产者/消费者模型中内存序的疑问
C++内存模型:生产者-消费者示例中的重排问题解答
问题1:waitForJob中如何阻止存储操作重排
对应代码:
void waitForJob() { assert(!inputValid()); mWorkerBusy.store(false, std::memory_order_release); { std::unique_lock lk{mMutex}; mCV.wait(lk, [&] { return inputValid() || stop(); }); } }
有两个关键机制阻止mWorkerBusy.store(false)被重排到mCV.wait()之后:
- release语义的内存屏障:
std::memory_order_release会强制当前线程中,该存储操作之前的所有读写操作,都不能被重排到这个存储之后。也就是说store(false, release)必须在后续的锁构造、wait调用前完成。 - 互斥锁的内存同步保证:
std::unique_lock构造时对mMutex加锁,加锁操作隐含获取语义的内存屏障,会阻止后续wait操作被重排到加锁前的任何操作(包括store(false))。
双重约束下,store(false)一定会在wait执行前完成,不会出现重排导致mWorkerBusy始终为true的情况。
问题2:submitJob中如何阻止notify操作提前执行
对应代码:
template <typename T> void submitJob(T&& input) { assert(ready()); { std::lock_guard lk{mMutex}; mInput.slot = std::forward<T>(input); } mWorkerBusy.store(true, std::memory_order_relaxed); mCV.notify_one(); }
核心是同一线程内的顺序一致性保证:C++标准明确规定,同一线程中的操作必须按照代码书写顺序呈现给自身。哪怕store用的是memory_order_relaxed(不提供跨线程同步语义),编译器和CPU也不会把后续的notify_one()重排到store(true)之前。
另外,lock_guard销毁时释放互斥锁的操作带有release语义,确保mInput.slot的写入在store(true)前对其他线程可见,但这和store与notify的顺序无关——哪怕没有互斥锁,同一线程里notify也不会跑到store前面。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

