c++ multithreading c++11 concurrency volatile

¿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:

  1. Dos optimizaciones pueden ser para std::atomic<int> a; , pero no puede ser para volatile int a; :

    • operaciones fusionadas: a = 1; a = 2; a = 1; a = 2; puede ser reemplazado por el compilador en a = 2;
    • propagación constante: a = 1; local = a; a = 1; local = a; puede ser reemplazado por el compilador en a = 1; local = 1; a = 1; local = 1;
  2. 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ómica a.load(std::memory_order_...);

Es decir, volatile no introduce vallas de memoria, pero std::atomic puede hacerlo.

Como bien se describe en el artículo:

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;

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?

  1. Como en volatile : evita las operaciones fusionadas y la propagación constante como se describe al principio de la pregunta
  2. 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.