Mutex en Golang con ejemplos

Un Mutex es un método utilizado como mecanismo de bloqueo para garantizar que solo un Goroutine acceda a la sección crítica del código en cualquier momento. Esto se hace para evitar que ocurran condiciones de carrera. El paquete de sincronización contiene el Mutex. Dos métodos definidos en Mutex

  • Cerrar
  • desbloquear

Cualquier código presente entre una llamada a Bloquear y Desbloquear será ejecutado por un solo Goroutine.

mutex.Lock() 

x = x + 1 // this statement be executed
          // by only one Goroutine 
          // at any point of time  

mutex.Unlock()

Si un Goroutine ya tiene el bloqueo y si un nuevo Goroutine está tratando de obtener el bloqueo, entonces el nuevo Goroutine se detendrá hasta que se desbloquee el mutex. Para entender este concepto, primero entendamos un programa que tiene condiciones de carrera.

Programa con condición de carrera

Aquí hay un ejemplo de un programa que encuentra una condición de carrera

// Program with race condition
package main  
import (  
    "fmt"
    "sync" // to import sync later on
)
var GFG  = 0
  
// This is the function we’ll run in every
// goroutine. Note that a WaitGroup must
// be passed to functions by pointer.  
func worker(wg *sync.WaitGroup) {  
    GFG = GFG + 1
  
    // On return, notify the 
    // WaitGroup that we’re done.
    wg.Done()
}
func main() { 
  
    // This WaitGroup is used to wait for 
    // all the goroutines launched here to finish. 
    var w sync.WaitGroup
  
    // Launch several goroutines and increment
    // the WaitGroup counter for each
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go worker(&w)
    }
    // Block until the WaitGroup counter
    // goes back to 0; all the workers 
    // notified they’re done.
    w.Wait()
    fmt.Println("Value of x", GFG)
}

Explicación: En el programa anterior, la función de trabajador en la línea no. 12 incrementa el valor de GFG en 1 y luego llama a Done() en WaitGroup para informar su finalización. La función de trabajador se llama 1000 veces. Cada uno de estos Goroutines se ejecutan simultáneamente y la condición de carrera ocurre cuando se intenta incrementar GFG en la línea no. 13, ya que varios Goroutines intentan acceder al valor de GFG al mismo tiempo. Ejecutar el mismo programa varias veces da resultados diferentes cada vez debido a la condición de carrera.

Recuerde una cosa, si verifica la salida del programa anterior usando el compilador en línea, es posible que obtenga la misma salida cada vez (sin condición de carrera) debido a la naturaleza determinista. Así que use el compilador local como Visual Studio o CMD para ver los resultados.

Resolviendo el problema anterior usando Mutex

Aquí hay un ejemplo de un programa que determina cómo se corrige la condición de carrera.

// Program with race condition fixed by mutex
package main  
import (  
    "fmt"
    "sync" // to import sync later on
)
var GFG  = 0
  
// This is the function we’ll run in every
// goroutine. Note that a WaitGroup must
// be passed to functions by pointer.  
func worker(wg *sync.WaitGroup, m *sync.Mutex) { 
    // Lock() the mutex to ensure 
    // exclusive access to the state, 
    // increment the value,
    // Unlock() the mutex
    m.Lock() 
    GFG = GFG + 1
    m.Unlock()
  
    // On return, notify the 
    // WaitGroup that we’re done.
    wg.Done()
}
func main() { 
    // This WaitGroup is used to wait for 
    // all the goroutines launched here to finish. 
    var w sync.WaitGroup
  
    // This mutex will synchronize access to state.
    var m sync.Mutex
  
    // Launch several goroutines and increment
    // the WaitGroup counter for each
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go worker(&w, &m)
    }
    // Block until the WaitGroup counter
    // goes back to 0; all the workers 
    // notified they’re done.
    w.Wait()
    fmt.Println("Value of x", GFG)
}

Salida:
Valor de x 1000

Explicación: Mutex es un tipo de estructura y la variable m de tipo Mutex se crea en la línea no. 31. La función del trabajador se cambia para que el código que incrementa GFG en la línea no. 18 entre m.Lock() y m.Unlock() . Ahora solo se permite que un Goroutine ejecute este fragmento de código en cualquier momento y, por lo tanto, se trata la condición de carrera.

La dirección de mutex debe pasarse en la línea no. 37. Si la exclusión mutua se pasa por valor, cada Goroutine tendrá su propia copia de la exclusión mutua y la condición de carrera aún persistirá.

Publicación traducida automáticamente

Artículo escrito por AnikashChakraborty y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *