gpt4 book ai didi

linux - Linux 上的内存屏障和 atomic_t

转载 作者:IT王子 更新时间:2023-10-28 23:54:33 32 4
gpt4 key购买 nike

最近在看一些Linux内核空间的代码,看到这个

uint64_t used;
uint64_t blocked;

used = atomic64_read(&g_variable->used); //#1
barrier(); //#2
blocked = atomic64_read(&g_variable->blocked); //#3

这段代码的语义是什么?它是否确保#1 通过#2 在#3 之前执行。但是我有点困惑,因为

#A 在64位平台,atomic64_read宏扩展为

used = (&g_variable->used)->counter           // where counter is volatile.

在 32 位平台上,它被转换为使用锁 cmpxchg8b。我假设这两个具有相同的语义,对于 64 位版本,我认为这意味着:

  1. 全有或全无,我们可以排除地址未对齐且字长大于 CPU 的 native 字长的情况。
  2. 无优化,强制 CPU 从内存位置读取。

atomic64_read 没有保留读取顺序的语义!!!参见this

#B barrier 宏定义为

/* Optimization barrier */
/* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory")

来自wiki this只是防止 gcc 编译器 重新排序读写。

我感到困惑的是它如何禁用 CPU 的重新排序优化?另外,我可以认为barrier macro是full fence吗?

最佳答案

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 - Linux 上的内存屏障和 atomic_t,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6555462/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com