¿Qué es un deadlock al trabajar con goroutine?
sobes.tech AI
Respuesta de la IA
El bloqueo (deadlock) es una situación en la que dos o más goroutines se bloquean mutuamente esperando unas a otras, y ninguna puede continuar su ejecución. Ocurre con mayor frecuencia al trabajar con mutexes o canales.
Ejemplos de deadlock:
-
Bloqueo de mutexes en orden diferente:
// Ejemplo de deadlock con mutexes var mu1 sync.Mutex var mu2 sync.Mutex func goroutine1() { mu1.Lock() // Bloquea mu1 time.Sleep(100 * time.Millisecond) // Espera un poco mu2.Lock() // Intenta bloquear mu2 (ocupado por goroutine2) fmt.Println("goroutine1 adquirió mu2") mu2.Unlock() mu1.Unlock() } func goroutine2() { mu2.Lock() // Bloquea mu2 time.Sleep(100 * time.Millisecond) // Espera un poco mu1.Lock() // Intenta bloquear mu1 (ocupado por goroutine1) fmt.Println("goroutine2 adquirió mu1") mu1.Unlock() mu2.Unlock() }Goroutine1 bloqueó
mu1y esperamu2. Goroutine2 bloqueómu2y esperamu1. Ambas goroutines están bloqueadas. -
Enviar a un canal sin buffer sin receptor:
// Ejemplo de deadlock con canal func main() { ch := make(chan int) //go func() { // Si no se inicia una goroutine para leer, habrá deadlock // <-ch //}() ch <- 1 // Envío al canal sin receptor activo fmt.Println("Enviado al canal") // Esta línea no se alcanzará }El envío a un canal sin buffer se bloquea hasta que otra goroutine comience a leer de él. Si no hay receptor, se produce un deadlock.
-
Lectura de un canal sin remitente (después de cerrar o con buffer vacío):
// Ejemplo de deadlock al leer de un canal func main() { ch := make(chan int, 1) // Canal con buffer de 1 elemento ch <- 1 // Enviamos 1 close(ch) // Cerramos el canal <-ch // Leemos 1 <-ch // Intentamos leer de nuevo de un canal cerrado y vacío - deadlock }La lectura de un canal cerrado y no vacío terminará con éxito. La lectura de un canal cerrado y vacío o de un canal abierto pero vacío sin remitente provocará bloqueo.
El runtime de Golang puede detectar ciertos tipos de deadlocks (por ejemplo, cuando todas las goroutines bloqueadas esperan recibir o enviar a una única goroutine), y en ese caso, el programa terminará abruptamente con el mensaje "fatal error: all goroutines are asleep - deadlock!". Sin embargo, no todos los deadlocks pueden ser detectados automáticamente.
Para prevenir deadlocks, es importante:
- Mantener un orden consistente en la adquisición de mutexes.
- Asegurarse de que cada envío a un canal sin buffer tenga una lectura correspondiente, y viceversa.
- Utilizar
selectcon la ramadefaulto timeouts al trabajar con canales cuando sea necesario. - Gestionar cuidadosamente el tiempo de vida de las goroutines y el cierre de canales.