std::atomic_thread_fence
| Definido en el archivo de encabezado <atomic>
|
||
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept; |
(desde C++11) | |
Establece un ordenamiento de sincronización de memoria de accesos no atómicos y relajados, como se indica por order, sin una operación atómica asociada.
Sincronización de barrera a operación atómica
Una barrera de liberación F en el hilo A se sincroniza con una operación de adquisición Y en el hilo B, si
- existe un almacenamiento atómico X (con cualquier ordenamiento de memoria);
- Y lee el valor escrito por X (o el valor sería escrito por la secuencia de liberación encabezada por X si X fuera una operación de liberación);
- F es secuenciada antes que X en el hilo A.
En este caso, los almacenamientos no atómicos y atómicos relajados que son secuenciados-antes que F en el hilo A sucederán-antes que todas las cargas no atómicas y atómicas relajadas desde las mismas ubicaciones hechas en el hilo B después de Y.
Sincronización de operación atómica a barrera
Una operación de liberación atómica X en el hilo A se sincroniza-con una barrera de adquisición F en el hilo B, si
- existe una lectura atómica Y (con cualquier ordenamiento de memoria);
- Y lee el valor escrito por X (o por la secuencia de liberación encabezada por X);
- Y es secuenciada antes que F en el hilo B.
En este caso, los almacenamientos no atómicos y atómicos relajados que son secuenciados-antes que X en el hilo A sucederán-antes que todas las cargas no atómicas y atómicas relajadas desde las mismas ubicaciones hechas en el hilo B después de F.
Sincronización de barrera a barrera
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 ordenamiento de memoria) que modifica a M en el hilo A;
- FA es secuenciada antes que X en el hilo A;
- existe una lectura atómica Y (con cualquier ordenamiento de memoria) en el hilo B;
- Y lee el valor escrito por X (o el valor sería escrito por la secuencia de liberación encabezada por X si X fuera una operación de liberación);
- Y es secuenciada antes que FB en el hilo B;
En este caso, los almacenamientos no atómicos y atómicos relajados que son secuenciados-antes que FA en el hilo A sucederán-antes que todas las cargas no atómicas y atómicas relajadas desde las mismas ubicaciones hechas en el hilo B después de FB.
Parámetros
| order | - | El ordenamiento de memoria ejecutado por esta barrera. |
Valor de retorno
(Ninguno)
Notas
atomic_thread_fence impone restricciones de sincronización más rígidas que una operación de almacenamiento atómica con el mismo std::memory_order. Mientras que una operación almacenar-liberar evita que todas las escrituras anteriores se muevan más allá de la operación almacenar-liberar, un atomic_thread_fence con ordenamiento memory_order_release evita que todas las escrituras anteriores se muevan más allá de todos los almacenamientos posteriores.
La sincronización de barrera a barrera se puede usar 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 valores ya calculados entre 0 y 3
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 ser -1, algunas o todas.
// 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
Escanear una variedad de buzones de correo y procesar solo los que están destinados a nosotros, sin sincronizaciones innecesarias. Este ejemplo usa la sincronización de operación atómica a barrera.
const int num_mailboxes = 32;
std::atomic<int> mailbox_receiver[num_mailboxes];
std::string mailbox_data[num_mailboxes];
// Los hilos escritores actualizan los datos no atómicos compartidos
// y luego actualizan a 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 sincronizarse con uno
for (int i = 0; i < num_mailboxes; ++i) {
if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) {
std::atomic_thread_fence(std::memory_order_acquire); // sincronizar con solo un escritor
do_work( mailbox_data[i] ); // garantizado que observa todo lo hecho por el hilo escritor
// antes de atomic_store_explicit()
}
}
Véase también
(C++11) |
Define las restricciones del ordenamiento de memoria para la operación atómica dada. (typedef) |
(C++11) |
Barrera entre un hilo y un controlador de señales ejecutados en el mismo hilo/subproceso. (función) |
Documentación de C para atomic_thread_fence
| |