原子读取是否保证读取最新值?

TwI*_*ITe 7 c++ multithreading atomic volatile

在 C++ 中,我们有关键字volatileatomic类。它们之间的区别是,volatile 不保证线程安全的并发读写,而只是保证编译器不会将变量的值存储在缓存中,而是从内存中加载变量,而 atomic 保证线程安全的并发读写。

众所周知,原子读操作是不可分割的,即当一个或多个线程读取变量的值时,两个线程都不能将新值写入变量,所以我认为我们总是读取最新值,但我不确定:)

所以,我的问题是:如果我们声明原子变量,我们是否总是获得变量调用load()操作的最新值

Dan*_*man 4

当我们谈论现代架构上的内存访问时,我们通常会忽略读取值的“确切位置”。

读操作可以从缓存(L0/L1/...)、RAM 甚至硬盘驱动器(例如,当内存交换时)获取数据。

这些关键字告诉编译器在访问数据时要使用哪些汇编操作。

易挥发的

一个关键字,告诉编译器始终从内存中读取变量的值,而不是从寄存器中读取。

该“内存”仍然可以是高速缓存,但是,如果高速缓存中的该“地址”被认为是“脏”,这意味着该值已被不同的处理器更改,则该值将被重新加载。

这确保我们永远不会读取过时的值。

澄清:根据标准,如果volatile类型不是基元,其读/写操作本质上是原子的(就读/写它的汇编指令而言),则可能会读取一个中间值(编写者设法当读者读取它时只写入一半字节)。然而,现代的实现并不是这样的。

原子

当编译器看到load(读取)操作时,它基本上会执行与对值执行的操作完全相同的操作volatile

那么区别是什么呢???

区别在于跨CPU写操作。使用易失性变量时,如果 CPU 1 设置该值,而 CPU 2 读取该值,则读取器可能会读取旧值。

但是,怎么可能呢?易失性关键字保证我们不会读取过时的值!

嗯,那是因为作者没有公布这个值!尽管读者试图阅读它,但它读的是旧的。

当编译器偶然发现store原子变量的(写入)操作时:

  • 在内存中自动设置值
  • 宣布值已更改

宣布后,所有 CPU 都会知道它们应该重新读取变量的值,因为它们的缓存将被标记为“脏”。

这种机制与对文件执行的操作非常相似。当您的应用程序写入硬盘驱动器上的文件时,其他应用程序可能会也可能看不到新信息,具体取决于您的应用程序是否将数据刷新到硬盘驱动器。

如果数据没有刷新,那么它只是驻留在应用程序缓存中的某个位置并且仅其自身可见。一旦刷新它,任何打开该文件的人都会看到新的状态。

澄清:常见的现代编译器和缓存实现volatile也确保写入的正确发布。然而,这并不是更喜欢它的理由std::atomic。例如,就像一些评论指出的那样,Linux 对 x86_64 的原子读写是使用volatiles.


归档时间:

查看次数:

1712 次

最近记录:

7 年 前