Sobes.tech
Middle

¿Cómo se puede sincronizar la interacción entre hilos?

sobes.tech AI

Respuesta de la IA

Existen varios mecanismos principales de sincronización de hilos en C++:

  • Mutexes: Garantizan exclusión mutua. Solo un hilo puede poseer un mutex en un momento dado. Se utilizan para proteger recursos compartidos contra accesos simultáneos.

    #include <mutex>
    
    std::mutex myMutex;
    
    void criticalSection() {
        std::lock_guard<std::mutex> lock(myMutex); // Adquisición del mutex
        // Trabajo con recurso compartido
    } // El mutex se libera automáticamente al salir del ámbito
    
  • Semáforos: Controlan el acceso a recursos limitados. Tienen un contador que indica la cantidad de recursos disponibles. Los hilos pueden disminuir (para obtener un recurso) o aumentar (para liberar).

    #include <semaphore.h> // Generalmente en sistemas POSIX
    
    sem_t mySemaphore;
    
    void initSemaphore(int count) {
        sem_init(&mySemaphore, 0, count); // Inicialización del semáforo con contador count
    }
    
    void acquireResource() {
        sem_wait(&mySemaphore); // Decrementa el contador, bloquea si es 0
        // Uso del recurso
    }
    
    void releaseResource() {
        sem_post(&mySemaphore); // Incrementa el contador
    }
    
  • Variables de condición: Permiten que los hilos esperen a que se cumpla una condición. Generalmente se usan junto con mutexes. Un hilo que espera libera el mutex y se bloquea hasta que otro hilo le notifique que la condición se cumple.

    #include <condition_variable>
    #include <mutex>
    #include <queue>
    
    std::condition_variable myCondition;
    std::mutex myMutex;
    std::queue<int> myQueue;
    
    void producer(int value) {
        std::lock_guard<std::mutex> lock(myMutex);
        myQueue.push(value);
        myCondition.notify_one(); // Notifica a un hilo en espera
    }
    
    int consumer() {
        std::unique_lock<std::mutex> lock(myMutex);
        myCondition.wait(lock, [&]{ return !myQueue.empty(); }); // Espera a la condición
        int value = myQueue.front();
        myQueue.pop();
        return value;
    }
    
  • Variables atómicas: Permiten realizar operaciones simples (lectura, escritura, modificación) de forma atómica, sin necesidad de mutexes para esas operaciones específicas.

    #include <atomic>
    
    std::atomic_int atomicCounter(0);
    
    void incrementCounter() {
        atomicCounter++; // Incremento atómico
    }
    
  • Barrera: Sincronizan varios hilos para que ninguno pueda continuar hasta que todos hayan llegado a la barrera.

    #include <barrier> // C++20
    
    std::barrier myBarrier(3); // Barrera para 3 hilos
    
    void workerThread() {
        // Realización de parte del trabajo
        myBarrier.arrive_and_wait(); // Espera a que todos lleguen a la barrera
        // Realización de la siguiente parte del trabajo
    }
    

La elección de un mecanismo específico depende de la naturaleza de la interacción entre los hilos:

  • Mutexes: La forma más común de proteger datos compartidos.
  • Semáforos: Gestión del acceso a recursos limitados.
  • Variables de condición: Espera a que ocurra un evento o estado específico.
  • Variables atómicas: Ejecución eficiente de operaciones simples y atómicas.
  • Barrera: Sincronización de hilos para avanzar conjuntamente a la siguiente etapa.