Biblioteca estándar de C++<atomic>
En la programación multihilo, la sincronización de datos y la seguridad de los hilos son un problema importante.
El estándar C++11 introdujo la biblioteca<atomic><atomic>, que proporciona un conjunto de operaciones atómicas para garantizar que el acceso a un único dato en un entorno multihilo sea atómico, es decir, indivisible. Esto evita carreras de datos y garantiza la seguridad de los hilos.
Una operación atómica es aquella que no puede ser interrumpida por otros hilos durante su ejecución.
<atomic>Los tipos atómicos de la biblioteca <atomic> proporcionan este tipo de operaciones, garantizando que el acceso a datos compartidos en un entorno multihilo sea seguro.
Sintaxis
<atomic>La biblioteca proporciona varios tipos atómicos, incluyendoatomic<bool>, atomic<char>, atomic<short>, atomic<int>, atomic<long>, atomic<long long>, atomic<wchar_t>, atomic<char16_t>, atomic<char32_t>, atomic<unsigned char>, atomic<unsigned short>, atomic<unsigned>, atomic<unsigned long>, atomic<unsigned long long>, atomic<float>, atomic<double>, atomic<long double>etc.
Operaciones básicas
load(): leer de forma segura el valor de una variable atómica.store(value): escribir de forma segura un valor en una variable atómica.exchange(value): reemplazar el valor de la variable atómica porvalue, y devolver el valor anterior de la variable atómica.compare_exchange_weak(expected, desired): si el valor actual de la variable atómica es igual aexpected, entonces se establece endesired, y se devuelvetrue. De lo contrario, se estableceexpectedcomo el valor actual de la variable atómica, y se devuelvefalse。compare_exchange_strong(expected, desired): similar acompare_exchange_weak, pero en bucle hasta que tenga éxito.
Ejemplo
A continuación se muestra un ejemplo simple que utiliza la biblioteca<atomic><atomic>, que demuestra cómo actualizar de forma segura un contador compartido en un entorno multihilo.
Ejemplo
#include <atomic>
#include <thread>
std::atomic<int> counter(0); // Inicializar el contador atómico
void increment() {
for (int i = 0; i < 10000; ++i) {
counter.fetch_add(1, std::memory_order_relaxed); // Incremento atómico
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl; // Imprimir el valor final del contador
return 0;
}
Al ejecutar el programa anterior, verás una salida similar a:
Final counter value: 20000
Esta salida indica que los dos hilos incrementaron cada uno el contador 10000 veces sin carreras de datos, de forma exitosa.
Notas
- Al usar la biblioteca
<atomic><atomic>, asegúrate de que todo acceso a datos compartidos se realice mediante operaciones atómicas para evitar carreras de datos. - Las diferentes operaciones atómicas tienen diferentes requisitos de orden de memoria,
std::memory_order_relaxedmemory_order_relaxed es el requisito de orden de memoria más bajo, pero puede no garantizar la visibilidad de las operaciones. Elige el orden de memoria adecuado según tus necesidades. - La sobrecarga de rendimiento de las operaciones atómicas suele ser mayor que la de las operaciones no atómicas, por lo que en entornos de un solo hilo, usar variables normales puede ser más eficiente.
Mediante el uso de la biblioteca<atomic><atomic>, los programadores de C++ pueden escribir código seguro para hilos más fácilmente, manteniendo al mismo tiempo un alto rendimiento.