Sobes.tech
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 operador select com uma cláusula default ou 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
	}
}