内存屏障和Linux上的atomic_t
最近,我正在阅读一些Linux内核空间代码,我看到了
uint64_t used;uint64_t blocked;
used = atomic64_read(&g_variable->used); //#1
barrier(); //#2
blocked = atomic64_read(&g_variable->blocked); //#3
该代码段的语义是什么?是否确保#1在#3之前由#2执行。但是我有点乱,因为
在64位平台上,atomic64_read宏扩展为
used = (&g_variable->used)->counter // where counter is volatile.
在32位平台中,将其转换为使用锁 。我认为这两个具有相同的语义,对于64位版本,我认为这意味着:
- ,我们可以排除地址未对齐且字长大于CPU本机字长的情况。
- ,强制CPU从内存位置读取。
看到这个
的 宏定义为
/* Optimization barrier *//* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory")
在Wiki中,这只是防止
重新排列读写顺序。
我很困惑的是它如何禁用CPU的重新排序优化?另外,我可以认为屏障宏是完整的栅栏吗?
回答:
32位x86处理器不能为64位类型提供简单的原子读取操作。在此类处理“普通”寄存器的CPU上,对64位类型唯一的原子操作是LOCK
CMPXCHG8B,这就是为什么在此使用它的原因。另一种选择是使用MOVQ
和MMX /
XMM寄存器,但是这需要了解FPU状态/寄存器,并且需要使用MMX / XMM指令完成对该值的所有操作。
在64位x86_64处理器上,对64位类型的对齐读取是原子的,并且可以通过一条MOV
指令完成,因此仅需要进行普通读取—
的使用volatile
只是为了确保编译器实际进行读取,并且不缓存先前的值。
至于读取顺序,您引用的内联汇编程序可确保编译器以正确的顺序发出指令,这是x86 / x86_64
CPU所需要的,只要写入顺序正确即可。LOCK
ed在x86上的写入具有总顺序;普通MOV
写提供了“因果一致性”,因此,如果线程A做到了,x=1
那么y=2
如果线程B进行了读取,y==2
则随后的读取x
将看到x==1
。
在IA-64中,的PowerPC,SPARC,和具有更宽松的存储器模型其它处理器很可能有更多的atomic64_read()
和barrier()
。
以上是 内存屏障和Linux上的atomic_t 的全部内容, 来源链接: utcz.com/qa/425602.html