Как известно, std::atomic
и volatile
- это разные вещи.Является ли стандартный C++ 11 гарантией того, что `volatile atomic <T>` имеет и семантику (volatile + atomic)?
Есть 2 основных отличия:
Две оптимизации может быть для
std::atomic<int> a;
, но не может быть дляvolatile int a;
:- конденсированных операций:
a = 1; a = 2;
могут быть заменены на компиляторa = 2;
- постоянное распространение:
a = 1; local = a;
может быть заменено компилятором наa = 1; local = 1;
- конденсированных операций:
Изменение порядка обыкновенных операций чтения/записи по атомным/летучий операций:
- для
volatile int a;
не может быть заказана любые летучие чтения/записи-операции. Но близкие обычные чтения/записи все еще могут быть переупорядочены вокруг изменчивых операций чтения/записи. - для
std::atomic a;
переназначения поблизости обычных чтения/записи ограничений, на основе барьера памяти, используемый для атомарной операцииa.load(std::memory_order_...);
- для
Т.е. volatile
не вводят забор памяти, но std::atomic
может это сделать.
Как хорошо описано в статье:
- Herb Sutter, 8 января 2009 - часть 1: http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484
- Herb Sutter, 8 января 2009 - часть 2: http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno=2
Например, std::atomic
следует использовать для параллельных многопоточных программ (CPU-Core < -> CPU-Core), но volatile
следует использовать для доступа к Mamory Mapped Regions на устройствах (CPU-Core < -> Устройство).
Но если требуется, и имеет необычную семантику и имеет какие-либо или все атомарность и/или заказ гарантий, необходимые для кодирования безблокировочного, т.е.если требуется volatile std::atomic<>
, требуется по нескольким причинам:
- заказа: для предотвращения изменения порядка обычные чтения/записи, например, для чтения из CPU-RAM, на который данные записаны с помощью устройств DMA-контроллер
Например:
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;
- разлив: процессор запись в CPU-RAM, а затем устройство DMA-контроллер чтение из этой памяти: https://en.wikipedia.org/wiki/Register_allocation#Spilling
пример:
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
- атомного: чтобы гарантировать, что летучая операция будет атомной - то есть он будет состоять из одной операции вместо нескольких - т.е. одной 8-байтовой операции вместо двух 4-байтовых операций
Для этого Herb Sutter говорит о volatile atomic<T>
, 8 января 2009: http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno=2
Наконец, чтобы выразить переменный, и обладает необычной семантикой и имеют любого или все атомарность и/или заказ гарантии, необходимую для кодирование без блокировки, только стандарт стандарта ISO C++ 0x обеспечивает прямой способ для его использования: изменчивый атомный.
Но делать современные стандартов C++ 11 (не C++ 0x проект), C++ 14 и C++ 17 гарантирует, что volatile atomic<T>
имеет и семантику (летучую + атомную)?
volatile atomic<T>
гарантирует самые строгие гарантии как от летучих, так и от атомных?
- Как и в
volatile
: Резкий конденсированную операцию и постоянное-распространение, как описано в начале вопроса - Как и в
std::atomic
: представляет заборы памяти, чтобы обеспечить упорядочение, разлив, и быть атомарным.
И мы можем сделать reinterpret_cast
от volatile int *ptr;
до volatile std::atomic<int>*
?
Позвольте мне кратко рассказать. 'volatile atomic' over 'atomic ' и почему вы хотите сделать 'reinterpret_cast'? Это, вероятно, будет работать, но не гарантируется. –
DeiDei
У вас не может быть 'std :: atomic', потому что волатильный тип не является тривиально копируемым. –
Brian
@Brian Да, вы правы. Удалено о 'std :: atomic'. –
Alex