Como pode sincronizar a interação entre threads?
sobes.tech IA
Resposta da IA
Existem vários mecanismos principais para sincronização e interação entre threads em C/C++:
-
Mutexes (Mutual Exclusion): Garantem acesso exclusivo a um recurso partilhado. O thread que adquire o mutex bloqueia os outros até o libertar.
#include <mutex> std::mutex my_mutex; void my_thread_function() { my_mutex.lock(); // Adquirir o mutex // Trabalhar com o recurso partilhado my_mutex.unlock(); // Libertar o mutex }Ou usando RAII:
#include <mutex> #include <lock_guard> std::mutex my_mutex; void my_thread_function() { std::lock_guard<std::mutex> lock(my_mutex); // Adquirir o mutex ao criar o objeto // Trabalhar com o recurso partilhado // O mutex é libertado automaticamente ao sair do escopo } -
Semáforos (Semaphores): Generalização dos mutexes. Mantêm um contador que permite a um número definido de threads acederem simultaneamente ao recurso.
#include <semaphore.h> // Para semáforos POSIX #include <windows.h> // Para semáforos Windows sem_t my_semaphore; // Semáforo POSIX void my_thread_function() { sem_wait(&my_semaphore); // Diminuir o contador do semáforo, bloquear se for 0 // Trabalhar com o recurso sem_post(&my_semaphore); // Aumentar o contador do semáforo }(Nota: A norma C++ não inclui semáforos diretamente, mas estão disponíveis através de bibliotecas do sistema ou implementações de terceiros.)
-
Variáveis de condição (Condition Variables): São usadas para que um thread espere que uma condição específica seja satisfeita, libertando o mutex nesse processo. Outro thread pode notificar que a condição foi cumprida.
#include <mutex> #include <condition_variable> std::mutex my_mutex; std::condition_variable my_cv; bool condition_met = false; void waiting_thread() { std::unique_lock<std::mutex> lock(my_mutex); my_cv.wait(lock, []{ return condition_met; }); // Esperar até a condição ser satisfeita // A condição foi satisfeita, trabalhar com o recurso } void notifying_thread() { std::unique_lock<std::mutex> lock(my_mutex); condition_met = true; lock.unlock(); // Libertar o mutex antes de notificar (opcional, mas recomendado) my_cv.notify_one(); // Notificar um thread em espera // ou // my_cv.notify_all(); // Notificar todos os threads em espera } -
Operações atômicas (Atomic Operations): Permitem realizar operações simples sobre variáveis (por exemplo, incremento, decremento) como uma ação indivisível, sem necessidade de bloqueio explícito com um mutex.
#include <atomic> std::atomic<int> counter(0); void my_thread_function() { counter++; // Incremento atômico // Ou: // counter.fetch_add(1); } -
Bloques de leitura-escrita (Shared Mutexes): Permitem que vários threads leiam dados simultaneamente, mas apenas um pode escrever.
#include <shared_mutex> // C++17 e superior std::shared_mutex my_shared_mutex; void read_thread() { my_shared_mutex.lock_shared(); // Adquirir para leitura // Ler dados my_shared_mutex.unlock_shared(); // Libertar para leitura } void write_thread() { my_shared_mutex.lock(); // Adquirir para escrita (exclusivo) // Escrever dados my_shared_mutex.unlock(); // Libertar para escrita } -
Barreiras: Permitem que um grupo de threads espere até que todos atinjam um ponto determinado na sua execução, antes de continuar.
#include <barrier> // C++20 std::barrier sync_point(4); // Barreira para 4 threads void my_thread_function() { // Trabalho antes da barreira sync_point.arrive_and_wait(); // Esperar até que todos atinjam a barreira // Trabalho após a barreira }
A escolha de um mecanismo específico depende da natureza da interação e dos recursos partilhados.