2012-03-17 39 views
6

que tienen un conjunto de funciones de C++:operaciones atómicas en C++

funcB(){}; 
funcC(){}; 
funcA() 
{ 
    funcB(); 
    funcC(); 
} 

Ahora quiero hacer funcA atómica, es decir funcB y funcC llamadas dentro funcA deben ser ejecutados de forma atómica. ¿Hay alguna forma de lograr esto?

+1

¿Puede explicar qué quiere decir con "ejecutada atómicamente"? Parece que solo quieres un 'std :: mutex'. – Potatoswatter

+1

Eso es probablemente lo que realmente quiere. – Joshua

+1

Quizás alguien debería mostrarle la sintaxis adecuada para usar un 'std :: mutex'. Quizás él no sabe. No sabría cómo usar un mutex en algunos otros idiomas. La explicación probablemente debería incluir la suposición de que todo el programa debe respetar el mutex. Es decir. el hilo B todavía puede invocar funcB y funcC, incluso si el hilo A lo hace bajo un mutex, a menos que el programador lo prohíba mediante el diseño. –

Respuesta

6

En general, NO. Las operaciones atómicas están definidas con mucha precisión. Lo que quieres es un semáforo o un mutex.

+0

Tenga en cuenta que si bien esta respuesta es estrictamente hablando correcta, la respuesta de Robᵩ es más útil para el usuario744829. – Joshua

11

Una forma de lograr esto es usar las nuevas características (C++ 11) std::mutex y std::lock_guard.

Para cada recurso protegido, crea una sola instancia global std::mutex; cada hilo bloquea entonces que mutex, ya que requiere, por la creación de un std::lock_guard:

#include <thread> 
#include <iostream> 
#include <mutex> 
#include <vector> 

// A single mutex, shared by all threads. It is initialized 
// into the "unlocked" state 
std::mutex m; 

void funcB() { 
    std::cout << "Hello "; 
} 
void funcC() { 
    std::cout << "World." << std::endl; 
} 
void funcA(int i) { 

    // The creation of lock_guard locks the mutex 
    // for the lifetime of the lock_guard 
    std::lock_guard<std::mutex> l(m); 

    // Now only a single thread can run this code 
    std::cout << i << ": "; 
    funcB(); 
    funcC(); 

    // As we exit this scope, the lock_guard is destroyed, 
    // the mutex is unlocked, and another thread is allowed to run 
} 

int main() { 
    std::vector<std::thread> vt; 

    // Create and launch a bunch of threads 
    for(int i =0; i < 10; i++) 
    vt.push_back(std::thread(funcA, i)); 

    // Wait for all of them to complete 
    for(auto& t : vt) 
    t.join(); 
} 

Notas:

  • En su ejemplo algún código no relacionado con funcA podría invocar cualquiera funcB o funcC sin honrar la bloquear ese conjunto funcA.
  • Dependiendo de cómo esté estructurado su programa, es posible que desee administrar la vida útil del mutex de forma diferente. Como ejemplo, es posible que desee ser un miembro de clase de la clase que incluye funcA.
1

Si está usando GCC 4.7 que puede utilizar la nueva memoria transaccional característica para hacer lo siguiente:

memoria transaccional tiene la intención de hacer la programación con hilos simples, en particular el acceso de sincronización de datos compartidos entre varios hilos utilizando transacciones. Al igual que con las bases de datos, una transacción es una unidad de trabajo que se completa en su totalidad o no tiene ningún efecto (es decir, las transacciones se ejecutan atómicamente). Además, las transacciones están aisladas entre sí de manera que cada transacción ve una vista coherente de la memoria.

Actualmente, las transacciones solo se admiten en C++ y C en forma de declaraciones de transacción, expresiones de transacción y transacciones de funciones. En el siguiente ejemplo, tanto a como b serán leídas y la diferencia se escribirán en c, todo atómicamente y aislada de otras transacciones:

__transaction_atomic { c = a - b; } 

Por lo tanto, otro hilo puede utilizar el siguiente código para actualizar b simultáneamente sin siempre causando c para mantener un valor negativo (y sin tener que utilizar otros constructos de sincronización, tales como bloqueos o C++ 11 atómica):

__transaction_atomic { if (a > b) b++; } 

la semántica precisos de las transacciones se definen en términos de la C++ 11/Modelo de memoria C1X (ver a continuación un enlace a la especificación). A grandes rasgos, las transacciones proporcionan garantías de sincronización que son similares a las que se garantizarían al usar un bloqueo global único como protección para todas las transacciones. Obsérvese que, al igual que otras construcciones de sincronización en C/C++, las transacciones dependen de un programa libre de carreras de datos (por ejemplo, una escritura no transaccional que es concurrente con una lectura transaccional en la misma ubicación de memoria es una carrera de datos).

Más información: http://gcc.gnu.org/wiki/TransactionalMemory

Cuestiones relacionadas