¿Qué es un mutex, qué tipos de mutex existen y cómo se utilizan?
sobes.tech AI
Respuesta de la IA
El mutex (del inglés MUTual EXclusion) es una primitiva de sincronización utilizada para garantizar el acceso exclusivo a un recurso compartido entre goroutines competidoras. Garantiza que en cualquier momento solo una goroutine pueda poseer el mutex y, por lo tanto, acceder a los datos protegidos.
En Go, el paquete sync proporciona dos tipos principales de mutexes:
-
sync.Mutex: Mutex estándar. Proporciona los métodosLock()yUnlock(). Si el mutex ya está bloqueado, la llamada aLock()bloquea la goroutine actual hasta que se libere.Unlock()desbloquea el mutex.var mu sync.Mutex var counter int func increment() { mu.Lock() // Bloquea el acceso a counter counter++ mu.Unlock() // Desbloquea el acceso } -
sync.RWMutex: Mutex para lectura/escritura. Permite que múltiples goroutines lean simultáneamente el recurso protegido, pero solo una escriba. Proporciona los métodosLock(),Unlock()(para escritura),RLock()yRUnlock()(para lectura).var rwMu sync.RWMutex var data []int func readData() { rwMu.RLock() // Bloquea para lectura // Leer data fmt.Println(data) rwMu.RUnlock() // Desbloquea lectura } func writeData(val int) { rwMu.Lock() // Bloquea para escritura // Escribe en data data = append(data, val) rwMu.Unlock() // Desbloquea escritura }
El uso de mutexes es necesario para prevenir condiciones de carrera (race conditions), cuando varias goroutines intentan modificar los mismos datos simultáneamente, lo que conduce a resultados impredecibles.
Reglas de uso:
- Llamar a
Lock()antes de acceder al recurso protegido. - Llamar a
Unlock()después de terminar el acceso. Se recomienda usardefer mu.Unlock()para garantizar la liberación incluso en caso de pánico. - No intentar bloquear un mutex ya bloqueado desde la misma goroutine (puede causar un bloqueo mutuo).
- No intentar desbloquear un mutex no bloqueado.
- Al usar
RWMutex, usarRLock/RUnlockpara operaciones de lectura yLock/Unlockpara escritura. - Los mutexes no deben copiarse después del primer uso. Páselos por referencia o puntero.
Ejemplo de uso de defer:
func safeIncrement() {
mu.Lock()
defer mu.Unlock() // Garantiza la liberación
counter++
}