内存屏障和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位版本,我认为这意味着:

  1. ,我们可以排除地址未对齐且字长大于CPU本机字长的情况。
  2. ,强制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所需要的,只要写入顺序正确即可。LOCKed在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

回到顶部