TwI*_*ITe 7 c++ multithreading atomic volatile
在 C++ 中,我们有关键字volatile和atomic类。它们之间的区别是,volatile 不保证线程安全的并发读写,而只是保证编译器不会将变量的值存储在缓存中,而是从内存中加载变量,而 atomic 保证线程安全的并发读写。
众所周知,原子读操作是不可分割的,即当一个或多个线程读取变量的值时,两个线程都不能将新值写入变量,所以我认为我们总是读取最新值,但我不确定:)
所以,我的问题是:如果我们声明原子变量,我们是否总是获得变量调用load()操作的最新值?
当我们谈论现代架构上的内存访问时,我们通常会忽略读取值的“确切位置”。
读操作可以从缓存(L0/L1/...)、RAM 甚至硬盘驱动器(例如,当内存交换时)获取数据。
这些关键字告诉编译器在访问数据时要使用哪些汇编操作。
一个关键字,告诉编译器始终从内存中读取变量的值,而不是从寄存器中读取。
该“内存”仍然可以是高速缓存,但是,如果高速缓存中的该“地址”被认为是“脏”,这意味着该值已被不同的处理器更改,则该值将被重新加载。
这确保我们永远不会读取过时的值。
澄清:根据标准,如果volatile类型不是基元,其读/写操作本质上是原子的(就读/写它的汇编指令而言),则可能会读取一个中间值(编写者设法当读者读取它时只写入一半字节)。然而,现代的实现并不是这样的。
当编译器看到load(读取)操作时,它基本上会执行与对值执行的操作完全相同的操作volatile。
区别在于跨CPU写操作。使用易失性变量时,如果 CPU 1 设置该值,而 CPU 2 读取该值,则读取器可能会读取旧值。
但是,怎么可能呢?易失性关键字保证我们不会读取过时的值!
嗯,那是因为作者没有公布这个值!尽管读者试图阅读它,但它读的是旧的。
当编译器偶然发现store原子变量的(写入)操作时:
宣布后,所有 CPU 都会知道它们应该重新读取变量的值,因为它们的缓存将被标记为“脏”。
这种机制与对文件执行的操作非常相似。当您的应用程序写入硬盘驱动器上的文件时,其他应用程序可能会也可能看不到新信息,具体取决于您的应用程序是否将数据刷新到硬盘驱动器。
如果数据没有刷新,那么它只是驻留在应用程序缓存中的某个位置并且仅其自身可见。一旦刷新它,任何打开该文件的人都会看到新的状态。
澄清:常见的现代编译器和缓存实现volatile也确保写入的正确发布。然而,这并不是更喜欢它的理由std::atomic。例如,就像一些评论指出的那样,Linux 对 x86_64 的原子读写是使用volatiles.
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           1712 次  |  
        
|   最近记录:  |