O que é um mutex, que tipos de mutex existem e como usá-los?
sobes.tech IA
Resposta da IA
O mutex (do inglês MUTual EXclusion) é uma primitiva de sincronização usada para garantir acesso exclusivo a um recurso compartilhado entre goroutines concorrentes. Ele garante que, em qualquer momento, apenas uma goroutine possa possuir o mutex e, consequentemente, acessar os dados protegidos.
No Go, o pacote sync fornece dois principais tipos de mutexes:
-
sync.Mutex: Mutex padrão. Fornece os métodosLock()eUnlock(). Se o mutex já estiver bloqueado, a chamada aLock()bloqueia a goroutine atual até que seja liberado.Unlock()desbloqueia o mutex.var mu sync.Mutex var counter int func increment() { mu.Lock() // Bloqueia o acesso ao counter counter++ mu.Unlock() // Desbloqueia o acesso } -
sync.RWMutex: Mutex para leitura/escrita. Permite que múltiplas goroutines leiam simultaneamente o recurso protegido, mas apenas uma escreva. Fornece os métodosLock(),Unlock()(para escrita),RLock()eRUnlock()(para leitura).var rwMu sync.RWMutex var data []int func readData() { rwMu.RLock() // Bloqueia para leitura // Leitura de data fmt.Println(data) rwMu.RUnlock() // Desbloqueia a leitura } func writeData(val int) { rwMu.Lock() // Bloqueia para escrita // Escrita em data data = append(data, val) rwMu.Unlock() // Desbloqueia a escrita }
O uso de mutexes é necessário para prevenir condições de corrida (race conditions), quando várias goroutines tentam modificar os mesmos dados simultaneamente, levando a resultados imprevisíveis.
Regras de uso:
- Chamar
Lock()antes de acessar o recurso protegido. - Chamar
Unlock()após terminar o acesso. Recomenda-se usardefer mu.Unlock()para garantir a liberação mesmo em caso de pânico. - Não tentar bloquear um mutex já bloqueado pela mesma goroutine (pode levar a deadlock).
- Não tentar desbloquear um mutex não bloqueado.
- Ao usar
RWMutex, usarRLock/RUnlockpara operações de leitura eLock/Unlockpara operações de escrita. - Os mutexes não devem ser copiados após o primeiro uso. Transmita-os por referência ou ponteiro.
Exemplo de uso de defer:
func safeIncrement() {
mu.Lock()
defer mu.Unlock() // Garante a liberação
counter++
}