仅用互斥锁保护对齐uint64访问是否合理?
我在部分生产代码中见过如下C++代码:假设变量x对齐到uint64,代码运行于X86系统。我了解X86系统中对对齐uint64值的读写属于原子操作,那么此处额外添加互斥锁的目的是什么?调用GetX()时虽持有互斥锁,但其他线程仍可能在该函数调用前后获取互斥锁并修改x,因此我认为该互斥锁并未提升代码安全性。
代码示例:
uint64 GetX() { Mutex l(&mutex); // (1) return x; }
首先要明确:X86上对齐的64位读写确实是原子的,但互斥锁的作用从来都不只是保证原子性,还有内存可见性和操作顺序性,甚至是和其他关联操作的同步。
内存可见性保障:如果没有互斥锁,即便
x的读写是原子的,其他线程对x的修改可能因为CPU缓存机制,无法被当前线程及时感知——当前线程可能一直读取缓存里的旧值。而互斥锁的加解锁操作会触发内存屏障(X86对应mfence类指令),强制刷新缓存,确保当前线程读到的是x的最新值。与写操作的配对同步:你只看到了读操作的
GetX(),但生产代码里必然存在对应的写逻辑(比如SetX(uint64 val)),且写操作大概率也会持有同一个互斥锁。这种情况下,互斥锁是用来保证读-写、写-写操作的顺序一致性:哪怕是单纯的赋值写,也能让读操作和写操作形成明确的先后关系,避免指令重排导致的逻辑混乱;如果写操作是“读-改-写”(比如x += 1),互斥锁还能保证整个操作的原子性,防止多线程竞争下的数值错误。代码扩展性:当前
x是单一的uint64,但未来需求变化时,可能需要在读取x的同时读取其他关联变量,或者在读取前后执行额外操作。提前加上互斥锁,能避免后续扩展时因遗漏同步逻辑引入线程安全问题。
你觉得互斥锁没用,是只孤立地看GetX()这一个函数,但线程安全是看整个系统的操作集合,不是单一函数的行为。
内容的提问来源于stack exchange,提问作者yacc45

