互斥锁(mutex)是否保证线程一定会将更新值写入主存?
互斥锁内存特性相关问题解答
问题a解答
对,所有符合工业标准的互斥锁实现,都会附带内存屏障语义保证可见性:
- 互斥锁
lock操作自带acquire内存屏障,保证拿锁后读取的共享变量都是最新值 - 互斥锁
unlock操作自带release内存屏障,保证临界区内对共享变量的所有修改,在释放锁之前全部同步到缓存一致性域,效果等价于最终写入主存,不会仅停留在当前线程的寄存器或者私有缓存中不对外暴露。下一个成功获取同一把锁的线程,一定能看到上一个持有锁线程对被保护变量的全部修改。
问题b解答
这个推论不成立,完全不等效于无缓存状态:
互斥锁的可见性保证底层依赖CPU的缓存一致性协议(比如常见的MESI协议)实现,没有禁用CPU缓存。被保护的变量在临界区运行期间仍然会保留在CPU缓存中,只是当其他核心需要访问该变量时,缓存一致性协议会自动同步不同核心的脏缓存行,不需要经过主存就能拿到最新值。我们说的“写入主存”只是逻辑上的抽象效果,不是实际的底层行为。
问题c解答
即使问题b的推论不成立,临界区仍然属于开销较高的代码段,需要尽可能精简:
- 互斥锁的
lock/unlock操作本身需要执行原子指令和内存屏障,执行开销是普通算术指令的几十到上百倍 - 如果出现多线程锁竞争,拿不到锁的线程会陷入内核态阻塞,触发上下文切换,开销会再上升几个数量级
如果临界区代码过长,会大幅提升锁竞争的概率,导致大量线程阻塞等待,整体程序吞吐量暴跌。因此不管有没有主存读写开销,都建议仅把操作共享变量的必要逻辑放在临界区内,无关逻辑全部移到锁外执行。
内容的提问来源于stack exchange,提问作者Physician
相关产品推荐
相关产品推荐

