Sobes.tech
Middle

¿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étodos Lock() y Unlock(). Si el mutex ya está bloqueado, la llamada a Lock() 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étodos Lock(), Unlock() (para escritura), RLock() y RUnlock() (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:

  1. Llamar a Lock() antes de acceder al recurso protegido.
  2. Llamar a Unlock() después de terminar el acceso. Se recomienda usar defer mu.Unlock() para garantizar la liberación incluso en caso de pánico.
  3. No intentar bloquear un mutex ya bloqueado desde la misma goroutine (puede causar un bloqueo mutuo).
  4. No intentar desbloquear un mutex no bloqueado.
  5. Al usar RWMutex, usar RLock/RUnlock para operaciones de lectura y Lock/Unlock para escritura.
  6. 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++
}