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.