使用__sync_lock_test_and_set后未调用__sync_lock_release是否强制?有何问题?
关于__sync_lock_test_and_set未匹配__sync_lock_release的问题分析
核心问题拆解
首先要明确:__sync_lock_test_and_set本质是为自旋锁实现设计的原子操作,它有两个核心行为:
- 原子地将目标内存的值替换为传入的
value,并返回原有的值; - 带有acquire内存语义——确保当前线程中,该操作之前的所有内存加载/存储,不会被编译器或CPU重排到这个操作之后。
而__sync_lock_release的作用是:将目标内存设为0,同时带有release内存语义——确保当前线程中,该操作之前的所有内存加载/存储,不会被重排到这个操作之后(让其他线程能看到这些操作的结果)。
你遇到的情况是原开发者误用了锁专用的原子函数来做哈希表指针的原子存储,未调用__sync_lock_release的影响分两种场景:
场景1:该内存位置仅用作原子指针存储,无锁逻辑
- 内存可见性风险:
__sync_lock_test_and_set的acquire语义只约束了当前线程的前置操作,但没有对应的release语义来“发布”后续操作。比如,你在设置指针后对指针指向的哈希表节点做初始化,编译器/CPU可能会把这些初始化操作重排到原子赋值之前。其他线程读取到这个指针后,访问节点时可能看到未初始化的垃圾数据。 - 无锁状态残留问题:这里反而要庆幸没调用
__sync_lock_release——因为这个函数会把目标内存强制设为0,直接清空你刚设置的哈希表指针,反而会导致严重的空指针错误。
场景2:该内存位置被其他代码当作锁变量使用
如果有其他线程依赖这个内存位置的“0值”作为“未锁定”标志(比如用__sync_bool_compare_and_swap尝试获取锁),那__sync_lock_test_and_set设置的非零指针值会让这些线程永远认为锁被持有,直接引发死锁或操作失败。但根据你的描述,原代码没有循环等待逻辑,这种场景的概率较低。
关于内存屏障的“留存”问题
内存屏障不是会“留存”的状态,它是操作执行时对内存重排的一次性约束:
__sync_lock_test_and_set的acquire屏障只在执行时生效,约束当前线程的内存操作顺序;- 没有release操作,只是缺失了对后续操作的发布语义,不会在系统中留下“残留屏障”影响其他无关代码。
建议方案
直接说服客户替换为新版GNU原子内置函数(如__atomic_store_n、__atomic_load_n)或C11标准的<stdatomic.h>接口,原因如下:
- 旧版
__sync_xxx系列已被GNU废弃,语义模糊容易误用; - 新版函数可以明确指定内存语义(如
__ATOMIC_RELEASE、__ATOMIC_ACQUIRE、__ATOMIC_SEQ_CST),完全匹配哈希表原子存储的需求,不会有锁相关的歧义。
比如,原子存储哈希表指针的正确写法(用新版GNU函数):
__atomic_store_n(&hash_entry->ptr, new_ptr, __ATOMIC_RELEASE);
内容的提问来源于stack exchange,提问作者Jeff Brower
相关产品推荐
相关产品推荐

