首页 文章

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

提问于
浏览
18

众所周知, std::atomicvolatile 是不同的东西 .

有两个主要区别:

  • 两个优化可以用于 std::atomic<int> a; ,但不能用于 volatile int a;

  • 融合操作: a = 1; a = 2; 可由 a = 2; 上的编译器替换

  • 常量传播: a = 1; local = a; 可由 a = 1; local = 1; 上的编译器替换

  • 跨原子/易失性操作重新排序普通读/写:

  • for volatile int a; 任何volatile-read / write-operations都无法重新排序 . 但附近的普通读/写仍然可以在易失性读/写周围重新排序 .

  • for 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<> ,则需要以下几个原因:

  • ordering :防止普通读/写的重新排序,例如,从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;

例:

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
  • 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 .

modern 标准C 11(不是C 0x草案),C 14和C 17是否保证 volatile atomic<T> 具有两种语义(易失性原子)?

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

  • volatile 中一样:避免融合操作和常量传播,如问题开头所述

  • std::atomic 中一样:引入内存栅栏以提供排序,溢出和原子化 .

我们可以 volatile int *ptr;volatile int *ptr;volatile std::atomic<int>* 吗?

1 回答

  • 4

    是的,它确实 .

    第29.6.5节,"Requirements for operations on atomic types"

    许多业务都是挥发性合格的 . “易失性设备寄存器”语义在标准中没有改变 . 此限定意味着在将这些操作应用于易失性对象时会保留波动性 .

    我检查了2008年到2016年的工作草案,所有这些都是相同的文字 . 因此,它应该应用C 11,C 14和C 17 .

相关问题