Sobes.tech
Middle

O que faz a sincronização no contexto de multithreading?

sobes.tech IA

Resposta da IA

A sincronização no contexto de multitarefa impede condições de corrida e garante um acesso consistente a recursos partilhados (variáveis, ficheiros, ligações de rede) de diferentes threads.

Os principais mecanismos de sincronização:

  • Mutex (exclusão mútua): Apenas um thread pode possuir o mutex e aceder ao recurso protegido.
  • Semaphore (semaforo): Limita o número de threads que podem aceder simultaneamente a um recurso. Funciona com um contador.
  • Lock (bloqueio): Conceito generalizado, frequentemente usado para se referir a mutex ou outros mecanismos que bloqueiam completamente o acesso.
  • Dispatch Queue (fila de despacho): No Grand Central Dispatch (GCD), as filas podem ser sequenciais (serial) ou concorrentes, garantindo sincronização através do controlo da ordem e do número de tarefas que são executadas simultaneamente. Filas sequenciais garantem a execução de tarefas uma de cada vez, o que fornece inerentemente sincronização para os dados acessados apenas a partir das tarefas dessa fila.

Princípio de funcionamento: Um thread que deseja aceder a um recurso partilhado tenta primeiro adquirir um bloqueio (obter lock). Se o recurso estiver livre, o thread obtém o bloqueio e trabalha com o recurso. Ao terminar, liberta o bloqueio (release lock). Se o recurso estiver ocupado, outros threads bloqueiam-se (esperam) até que o recurso seja libertado.

Exemplo de uso de mutex para proteger uma secção crítica:

// Exemplo em Objective-C usando @synchronized
- (void)updateSharedResource {
    @synchronized (self) { // Bloqueio no objeto self
        // Aqui é executada a secção crítica
        // O acesso a sharedResource é seguro
        self.sharedResource++;
    } // O bloqueio é libertado automaticamente ao sair do bloco
}
// Exemplo em Swift usando NSLock
let lock = NSLock()
var sharedCounter = 0

func incrementCounter() {
    lock.lock() // Tentativa de adquirir o bloqueio
    // Secção crítica
    sharedCounter += 1
    lock.unlock() // Libertar o bloqueio
}

A sincronização permite evitar problemas como:

  • Corrupção de dados.
  • Deadlock (bloqueio mútuo) de threads.
  • Livelock (bloqueios ativos) de threads.

A escolha do mecanismo de sincronização adequado depende da natureza da tarefa e do tipo de recurso.