Namespaces
Variants

std:: atomic_thread_fence

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
atomic_thread_fence
(C++11)
Free functions for atomic operations
Free functions for atomic flags
Definido en el encabezado <atomic>
extern "C" void atomic_thread_fence ( std:: memory_order order ) noexcept ;
(desde C++11)

Establece el orden de sincronización de memoria de accesos no atómicos y atómicos relajados, según lo indicado por order , sin una operación atómica asociada. Sin embargo, nótese que se requiere al menos una operación atómica para configurar la sincronización, como se describe a continuación.

Contenidos

Sincronización atómica de barreras

Una barrera de liberación F en el hilo A se sincroniza-con la operación atómica de adquisición Y en el hilo B , si

  • existe un almacenamiento atómico X (con cualquier orden de memoria),
  • Y lee el valor escrito por X (o el valor que sería escrito por la secuencia de liberación encabezada por X si X fuera una operación de liberación),
  • F está secuenciado-antes de X en el hilo A .

En este caso, todas las operaciones de almacenamiento no atómicas y atómicas relajadas que están secuenciadas-antes F en el hilo A ocurrirán antes-que todas las operaciones de carga no atómicas y atómicas relajadas de las mismas ubicaciones realizadas en el hilo B después de Y .

Sincronización con barreras atómicas

Una operación atómica de liberación X en el hilo A se sincroniza-con una barrera de adquisición F en el hilo B , si

En este caso, todas las operaciones de almacenamiento no atómicas y atómicas relajadas que están secuenciadas-antes X en el hilo A ocurrirán antes-que todas las operaciones de carga no atómicas y atómicas relajadas desde las mismas ubicaciones realizadas en el hilo B después de F .

Sincronización fence-fence

Una barrera de liberación FA en el hilo A se sincroniza-con una barrera de adquisición FB en el hilo B , si

  • existe un objeto atómico M ,
  • existe una escritura atómica X (con cualquier orden de memoria) que modifica M en el hilo A ,
  • FA está secuenciado-antes de X en el hilo A ,
  • existe una lectura atómica Y (con cualquier orden de memoria) en el hilo B ,
  • Y lee el valor escrito por X (o el valor que sería escrito por la secuencia de liberación encabezada por X si X fuera una operación de liberación),
  • Y está secuenciado-antes de FB en el hilo B .

En este caso, todas las operaciones de almacenamiento no atómicas y atómicas relajadas que están secuenciadas-antes FA en el hilo A ocurrirán antes-que todas las operaciones de carga no atómicas y atómicas relajadas de las mismas ubicaciones realizadas en el hilo B después de FB .

Dependiendo del valor del parámetro order , los efectos de esta llamada son:

Parámetros

order - el orden de memoria ejecutado por esta barrera

Notas

En x86 (incluyendo x86-64), atomic_thread_fence las funciones no emiten instrucciones de CPU y solo afectan el movimiento de código en tiempo de compilación, excepto para std :: atomic_thread_fence ( std:: memory_order_seq_cst ) .

atomic_thread_fence impone restricciones de sincronización más fuertes que una operación de almacenamiento atómico con el mismo std::memory_order . Mientras que una operación de almacenamiento-liberación atómica evita que todas las lecturas y escrituras anteriores se muevan más allá del almacenamiento-liberación, una atomic_thread_fence con ordenamiento std:: memory_order_release evita que todas las lecturas y escrituras anteriores se muevan más allá de todos los almacenamientos posteriores.

La sincronización fence-fence puede utilizarse para agregar sincronización a una secuencia de varias operaciones atómicas relajadas, por ejemplo:

// Global
std::string computation(int);
void print(std::string);
std::atomic<int> arr[3] = {-1, -1, -1};
std::string data[1000]; //datos no atómicos
// Hilo A, calcula 3 valores.
void ThreadA(int v0, int v1, int v2)
{
//  assert(0 <= v0, v1, v2 < 1000);
    data[v0] = computation(v0);
    data[v1] = computation(v1);
    data[v2] = computation(v2);
    std::atomic_thread_fence(std::memory_order_release);
    std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed);
    std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed);
}
// Hilo B, imprime entre 0 y 3 valores ya calculados.
void ThreadB()
{
    int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed);
    int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed);
    int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed);
    std::atomic_thread_fence(std::memory_order_acquire);
//  v0, v1, v2 podrían resultar ser -1, algunos o todos ellos.
//  De lo contrario, es seguro leer los datos no atómicos debido a las barreras:
    if (v0 != -1)
        print(data[v0]);
    if (v1 != -1)
        print(data[v1]);
    if (v2 != -1)
        print(data[v2]);
}

Ejemplo

Escanee un arreglo de buzones de correo, y procese solo los destinados a nosotros, sin sincronización innecesaria. Este ejemplo utiliza sincronización con barrera atómica.

const int num_mailboxes = 32;
std::atomic<int> mailbox_receiver[num_mailboxes];
std::string mailbox_data[num_mailboxes];
// Los hilos escritores actualizan datos compartidos no atómicos
// y luego actualizan mailbox_receiver[i] de la siguiente manera:
mailbox_data[i] = ...;
std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release);
// El hilo lector necesita verificar todos los mailbox[i], pero solo necesita sincronizar con uno.
for (int i = 0; i < num_mailboxes; ++i)
    if (std::atomic_load_explicit(&mailbox_receiver[i],
        std::memory_order_relaxed) == my_id)
    {
        // sincronizar con solo un escritor
        std::atomic_thread_fence(std::memory_order_acquire);
        // garantizado observar todo lo realizado en el hilo escritor
        // antes del atomic_store_explicit()
        do_work(mailbox_data[i]);
    }

Véase también

define las restricciones de ordenamiento de memoria para la operación atómica dada
(enum)
barrera entre un hilo y un manejador de señales ejecutado en el mismo hilo
(function)
Documentación C para atomic_thread_fence