多线程访问全局变量:是否需要使用互斥锁?
多线程读写全局变量是否需要互斥锁?
嘿,这个问题问到点子上了——咱们直接给结论:在这个场景下,不加互斥锁绝对是不安全的,而且必须要引入同步机制,我来拆解清楚背后的原因:
核心问题1:变量的可见性
就算g_flag是32位整数(看起来读写好像是“一次性完成”的),编译器和CPU的优化会给你挖大坑:
- 编译器可能会把
getFlag()里的读取操作优化成只从CPU缓存/寄存器里取旧值,不会每次都去主内存读取最新的g_flag。也就是说,线程thd1修改了g_flag之后,thd2可能永远看不到这个更新,一直读到旧值。 - 互斥锁的作用不只是“互斥”,更关键的是它会触发内存屏障:当thd1解锁
io_mutex时,会把修改后的g_flag强制刷新到主内存;当thd2加锁时,会强制从主内存重新读取g_flag,保证拿到的是最新值。
核心问题2:原子性的误区
很多人觉得“32位整数的读写是原子的,所以没问题”,但这是个错误的认知:
- C++标准并没有保证普通
std::int32_t的读写是原子操作,只有std::atomic系列类型的操作才是标准明确规定的原子操作。 - 就算在大多数现代CPU上32位读写是原子的,没有内存屏障的话,还是会出现上面说的可见性问题——线程之间的修改无法同步。
更好的替代方案?
如果只是单纯的读写一个整数,其实用std::atomic<std::int32_t>会比互斥锁更轻量:
static std::atomic<std::int32_t> g_flag; void setFlag(std::int32_t flag) { g_flag = flag; } std::int32_t getFlag() { return g_flag; }
原子类型本身就提供了可见性和原子性保证,不需要互斥锁就能安全地在多线程间读写。
总结
- 不管是用互斥锁还是原子类型,必须加同步机制,否则会出现变量不可见、甚至在某些特殊平台上的原子性问题。
- 不要依赖硬件的“默认原子性”,要严格遵循C++标准的同步规则。
内容的提问来源于stack exchange,提问作者Dmitry
相关产品推荐
相关产品推荐

