繁体   English   中英

在Linux内核中读写原子操作实现

[英]Read and Write atomic operation implementation in the Linux Kernel

最近,我已经深入研究了原子读写的Linux内核实现,并提出了一些问题。

首先是ia64架构的相关代码:

typedef struct {
    int counter;
} atomic_t;

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

#define atomic_set(v,i)     (((v)->counter) = (i))
#define atomic64_set(v,i)   (((v)->counter) = (i))
  1. 对于读取和写入操作,似乎采用直接方法来读取或写入变量。 除非在某处有另一个技巧,否则我不明白这个操作在汇编域中是否具有原子性的保证。 我想一个明显的答案是,这样的操作转换为一个程序集操作码,但即便如此,当考虑到不同的内存缓存级别(或其他优化)时,如何保证?

  2. 在读取宏上,volatile类型用于转换技巧。 任何人都知道这会如何影响这里的原子性? (注意,它不用于写操作)

我认为你误解了“非常模糊”的“原子”和“易变”这个词。 Atomic只是意味着单词将以原子方式读取或写入(一步完成,并保证此存储器位置的内容始终为一个写入或另一个,而不是介于两者之间)。 volatile关键字告诉编译器由于较早的读/写(从根本上说,永远不会优化掉读取),从不假设该位置的数据。

“原子”和“易变”这两个词在这里并不意味着存在任何形式的内存同步。 既不暗示任何读/写障碍或围栏。 关于内存和缓存一致性,没有任何保证。 这些功能在软件级别基本上只是原子功能,硬件可以根据其认为合适的优化/替代。

现在,为什么简单的阅读就足够了:每个架构的内存模型都不同。 许多体系结构可以保证对与某个字节偏移量对齐的数据进行原子读取或写入,或者长度为x个字等,并且因CPU而异。 Linux内核包含许多不同体系结构的定义,这些体系允许它在没有任何原子调用的情况下(基本上是CMPXCHG )保证(有时甚至仅在实践中,即使实际上他们的规范实际上并不保证)原子读取/写道。

至于volatile ,虽然除非你访问内存映射IO,否则一般不需要它,这一切都取决于调用atomic_readatomic_write宏的时间/地点/原因。 许多编译器 (虽然它不是在C规格设定)产生volatile变量的内存屏障/栅栏(GCC,把我的头顶部,是一个。MSVC不肯定的。)。 虽然这通常意味着对此变量的所有读/写现在都可以正式免除任何编译器优化,在这种情况下,通过创建“虚拟”volatile变量,只有这个特定的读/写实例才是优化的优化并重新订购。

读取在大多数主要体系结构上都是原子的,只要它们与大小的倍数对齐(并且不大于给定类型的读取大小),请参阅英特尔体系结构手册。 另一方面,写入许多不同,英特尔声称在x86下,单字节写入和对齐写入可能是原子的,在IPF(IA64)下,一切都使用获取和释放语义,这将使其保证原子,看到这一点

volatile阻止编译器在本地缓存该值,从而强制它在有权访问它的地方进行检索。

如果您针对特定体系结构编写,则可以对其进行特定的假设。
我想IA-64确实将这些东西编译成一条指令。

缓存不应该是一个问题,除非计数器跨越缓存行边界。 但如果需要4/8字节对齐,则不会发生这种情况。

当机器指令转换为两次存储器访问时,需要“真正的”原子指令。 这是增量(读取,增量,写入)或比较和交换的情况。

volatile会影响编译器可以执行的优化。
例如,它可以防止编译器将多个读取转换为一个读取。
但是在机器指令级别上,它什么也没做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM