标准C++ 11是否保证`volatile atomic <T>`具有语义(volatile + atomic)?

Ale*_*lex 19 c++ concurrency multithreading volatile c++11

众所周知,std::atomic并且volatile是不同的事情.

有两个主要区别:

  1. 两个优化可以是std::atomic<int> a;,但不能是volatile int a;:

    • 融合操作:a = 1; a = 2;可以由编译器替换a = 2;
    • 常量传播:a = 1; local = a;可以由编译器替换a = 1; local = 1;
  2. 跨原子/易失性操作重新排序普通读/写:

    • 对于volatile int a;任何易失性读/写操作都不能重新排序.但附近的普通读/写仍然可以在易失性读/写周围重新排序.
    • 用于std::atomic a;对基于用于原子操作的存储器屏障限制的附近普通读/写的重新排序a.load(std::memory_order_...);

volatile不介绍内存栅栏,但std::atomic可以做到.

正如文章中所描述的那样:

例如,std::atomic应该用于并发多线程程序(CPU-Core < - > CPU-Core),但volatile应该用于访问设备上的Mamory Mapped Regions(CPU-Core < - > Device).


但是如果需要,两者都具有不寻常的语义,并且具有无锁编码所需的任何或所有原子性和/或排序保证,即如果需要volatile std::atomic<>,需要有以下几个原因:

  • 排序:防止普通读/写的重新排序,例如,从CPU-RAM读取,使用Device DMA-controller写入数据

例如:

char cpu_ram_data_written_by_device[1024];
device_dma_will_write_here( cpu_ram_data_written_by_device );

// physically mapped to device register
volatile bool *device_ready = get_pointer_device_ready_flag();

//... somewhere much later
while(!device_ready); // spin-lock (here should be memory fence!!!)
for(auto &i : cpu_ram_data_written_by_device) std::cout << i;
Run Code Online (Sandbox Code Playgroud)

例:

char cpu_ram_data_will_read_by_device[1024];
device_dma_will_read_it( cpu_ram_data_written_by_device );

// physically mapped to device register
volatile bool *data_ready = get_pointer_data_ready_flag();

//... somewhere much later
for(auto &i : cpu_ram_data_will_read_by_device) i = 10;
data_ready=true; //spilling cpu_ram_data_will_read_by_device to RAM, should be memory fence
Run Code Online (Sandbox Code Playgroud)
  • atomic:保证volatile操作是原子的 - 即它将由单个操作而不是多个操作组成 - 即一个8字节操作而不是两个4字节操作

为此,Herb Sutter谈到volatile atomic<T>,2009年1月8日:http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno = 2

最后,为了表达一个变量,它既有不寻常的语义,又具有无锁编码所需的任何或全部原子性和/或排序保证,只有ISO C++ 0x草案标准提供了拼写它的直接方法:volatile atomic .

现代标准C++ 11(不是C++ 0x草案),C++ 14和C++ 17是否保证同时volatile atomic<T>具有语义(volatile + atomic)?

是否volatile atomic<T>保证挥发性和原子性的最严格保证?

  1. volatile:避免熔融操作和恒定传播中的问题的开始所描述的
  2. std::atomic:引入内存栅栏以提供排序,溢出和原子.

而且我们可以做reinterpret_castvolatile int *ptr;volatile std::atomic<int>*

vll*_*vll 5

是的,它确实。

第29.6.5节“对原子类型进行操作的要求”

许多操作都具有挥发性认证。在标准中,“作为设备寄存器的易失性”语义没有改变。这种限定意味着将这些操作应用于易失性对象时可以保留波动性。

我检查了2008年至2016年的工作草案,所有文件中都包含相同的案文。因此,它应适用于C ++ 11,C ++ 14和C ++ 17。