Middle
Como evitar uma situação de deadlock (interbloqueio) num programa em Go?
sobes.tech IA
Resposta da IA
O bloqueio mútuo em Go ocorre com mais frequência devido ao uso incorreto de mutexes e canais. Pode ser evitado das seguintes maneiras:
- Aquisição ordenada de mutexes: Ao adquirir múltiplos mutexes, faça-o sempre na mesma ordem em todas as goroutines.
- Timeouts para bloqueios: Use contextos com timeouts ao esperar por bloqueios ou receber de canais, para evitar esperas infinitas.
- Canais não bufferizados: Entenda que canais não bufferizados requerem tanto o emissor quanto o receptor para continuar a execução. Uso incorreto pode causar bloqueio.
- Canais bufferizados: Escolha corretamente o tamanho do buffer do canal. Um buffer muito pequeno pode causar bloqueio se emissores e receptores não estiverem sincronizados.
- Uso de
select: Quando trabalhar com múltiplos canais, use o operadorselectcom uma cláusuladefaultou timeout, para não ficar bloqueado esperando por um canal. - Análise de código: Use análise estática (
go vet,staticcheck) e ferramentas para detectar condições de corrida (go run -race), que também podem ajudar a identificar possíveis pontos de bloqueio mútuo. - Hierarquia de recursos: Se os recursos tiverem uma hierarquia, adquira-os de cima para baixo.
- Evitar dependências cíclicas: Não crie situações onde a goroutine A espera por um recurso ocupado por B, e B espera por um recurso ocupado por A.
Exemplo de uso de select com timeout:
import (
"context"
"time"
)
func exemplo(ch chan int) {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
select {
case val := <-ch:
// Processar valor
_ = val
case <-ctx.Done():
// Timeout ocorrido
}
}