¿El estándar C++ 11 garantiza que `volátil atómico<T>` tenga ambas semánticas(volátil+atómico)?
multithreading c++11 (1)
Como se sabe, std::atomic
and volatile
son cosas diferentes.
Hay 2 diferencias principales:
Dos optimizaciones pueden ser para
std::atomic<int> a;
, pero no puede ser paravolatile int a;
:- operaciones fusionadas:
a = 1; a = 2;
a = 1; a = 2;
puede ser reemplazado por el compilador ena = 2;
- propagación constante:
a = 1; local = a;
a = 1; local = a;
puede ser reemplazado por el compilador ena = 1; local = 1;
a = 1; local = 1;
- operaciones fusionadas:
Reordenamiento de lecturas / escrituras ordinarias a través de operaciones atómicas / volátiles:
- para
volatile int a;
cualquier operación de lectura / escritura volátil no se puede reordenar. Pero las lecturas / escrituras ordinarias cercanas todavía se pueden reordenar en torno a las lecturas / escrituras volátiles. - para
std::atomic a;
reordenamiento de lecturas / escrituras ordinarias cercanas restringidas según la barrera de memoria utilizada para la operación atómicaa.load(std::memory_order_...);
- para
Es decir, volatile
no introduce vallas de memoria, pero std::atomic
puede hacerlo.
Como bien se describe en el artículo:
- Herb Sutter, 8 de enero de 2009 - parte 1: http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484
- Herb Sutter, 8 de enero de 2009, parte 2: http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno=2
Por ejemplo, std::atomic
debe usar para programas de múltiples subprocesos concurrentes (CPU-Core <-> CPU-Core), pero la volatile
debe usar para acceder a las regiones mapeadas de Mamory en dispositivos (CPU-Core <-> Device) .
Pero si es necesario, ambos tienen una semántica inusual y tienen alguna o todas las garantías de atomicidad y / o ordenación necesarias para la codificación sin bloqueo, es decir, si es necesario. volatile std::atomic<>
, requiere por varias razones:
- orden : para evitar la reordenación de las lecturas / escrituras ordinarias, por ejemplo, para las lecturas de la CPU-RAM, en las que se escribieron los datos utilizando el controlador del dispositivo DMA
Por ejemplo:
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;
- derrame : la CPU escribe en la CPU-RAM y luego el dispositivo DMA-controlador lee desde esta memoria: https://en.wikipedia.org/wiki/Register_allocation#Spilling
ejemplo:
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
- atómico : para garantizar que la operación volátil será atómica, es decir, constará de una sola operación en lugar de múltiple, es decir, una operación de 8 bytes en lugar de dos operaciones de 4 bytes
Para esto, Herb Sutter dijo sobre el volatile atomic<T>
, 8 de enero de 2009: http://www.drdobbs.com/parallel/volatile-vs-volatile/212701484?pgno=2
Finalmente, para expresar una variable que tiene una semántica inusual y tiene alguna o todas las garantías de atomicidad y / o ordenación necesarias para la codificación sin bloqueo, solo el estándar ISO C ++ 0x draft proporciona una forma directa de deletrearlo: atómico volátil .
Pero, ¿ los estándares modernos C ++ 11 (no C ++ 0x draft), C ++ 14 y C ++ 17 garantizan que el volatile atomic<T>
tenga ambas semánticas (volátil + atómico)?
¿El volatile atomic<T>
garantiza las garantías más estrictas tanto de volátil como atómico?
- Como en
volatile
: evita las operaciones fusionadas y la propagación constante como se describe al principio de la pregunta - Como en
std::atomic
: introduce cercas de memoria para proporcionar ordenación, derrames y atómico.
Y podemos hacer reinterpret_cast
desde volatile int *ptr;
to volatile std::atomic<int>*
?
Si lo hace
Sección 29.6.5, "Requisitos para operaciones en tipos atómicos"
Muchas operaciones son volátiles calificadas. La semántica de "registro de dispositivo volátil" no ha cambiado en el estándar. Esta calificación significa que la volatilidad se conserva cuando se aplican estas operaciones a objetos volátiles.
Revisé los borradores de trabajo del 2008 al 2016, y el mismo texto está en todos ellos. Por lo tanto, debe aplicarse C ++ 11, C ++ 14 y C ++ 17.