Linux kernel 为什么arm原子读/写操作实现为易失性指针?

Linux kernel 为什么arm原子读/写操作实现为易失性指针?,linux-kernel,arm,arm64,atomicity,memory-barriers,Linux Kernel,Arm,Arm64,Atomicity,Memory Barriers,他是原子读取实现的示例: #define atomic_read(v) (*(volatile int *)&(v)->counter) 另外,我们是否应该在arm上显式地使用内存屏障进行原子操作?是的,转换为volatile是为了防止编译器假设v的值不能更改。至于使用内存屏障,GCC内置程序已经允许您指定所需的内存顺序,无需手动执行: GCC上的默认行为是使用\uuuuuu-ATOMIC\u-SEQ\u-CST

他是原子读取实现的示例:

#define atomic_read(v) (*(volatile int *)&(v)->counter)                                  

另外,我们是否应该在arm上显式地使用内存屏障进行原子操作?

是的,转换为volatile是为了防止编译器假设v的值不能更改。至于使用内存屏障,GCC内置程序已经允许您指定所需的内存顺序,无需手动执行:

GCC上的默认行为是使用
\uuuuuu-ATOMIC\u-SEQ\u-CST
,它将在Arm上发出必要的屏障,以确保您的原子按照您在代码中放置它们的顺序执行。为了优化ARM的性能,您将需要考虑使用较弱的语义来允许编译器避开障碍并让硬件执行得更快。有关Arm体系结构具有的内存屏障类型的更多信息,请参阅

他是原子读取实现的示例:

#define atomic_read(v) (*(volatile int *)&(v)->counter)                                  
实际上,这是一个有问题的问题,它假设一个cast不是一个nop,这是不能保证的

此外,我们是否应该明确使用内存屏障进行原子操作 手臂


可能吧。这取决于您正在做什么和期望什么。

显然是为了防止基于该值不会改变的假设的编译器时间优化。原子操作适用于内存单元,如果该值将缓存在寄存器中,这将毫无意义。关于障碍-一般来说,没有,但在特定上下文中可能需要。volatile表示编译器不优化读写。该表达式还强制生成地址(因此它强制对象在内存中,因此没有
寄存器)。注
volatile sig_atomic_t
在标准C中,因此它对所有编译器都有一定意义(不像
register
可以忽略)。上述定义不使用GCC的原子内置。我还认为称之为原子读取()会让人困惑。不会自动添加任何障碍的编译。也许问题应该是为什么这样做很好,因为这是内核如何实现它的。本文对此进行了解释:必须定义一个
atomic\u read\u acquire()
atomic\u set\u release()
,它们提供内存顺序。如果强制使用GCC,则代码来自早期的Linux ARM内核。上面的回答是正确的,这通常是错误的,但是OP发布时没有什么上下文,如果您使用GCC(尊重演员阵容),并且您不在SMP系统上(不需要障碍),宏没有任何错误。为了解决这些问题,更新了更新的内核(比如2014+)。看:改变是针对所有的拱门,而不仅仅是手臂。此外,如果您知道它是由单个CPU访问的,则不会有任何障碍。@artlessnoise“如果您使用GCC,宏没有问题”您在该宏上的源代码是什么?编译内核时,GCC的版本由头文件固定;如果没有,它将抛出一个错误,并且批准的GCC版本(当此操作处于活动状态时)将volatile视为重新加载。@artlessnoise是否有任何GCC版本承诺将强制转换为volatile的结果视为引用volatile obj?或者这是一个愉快的意外?
计数器本身就是一个原子;它可以在读取后缓存。重要的部分是读取整个值,而不仅仅是其中的一部分,并在序列点执行。我认为被接受的答案是错误的,只是添加了一条评论,认为你的答案更正确。