En aquest tema, explorarem com gestionar la concurrència en Go utilitzant mutexes per sincronitzar l'accés a recursos compartits. Els mutexes són una eina fonamental per evitar condicions de carrera i assegurar que només un goroutine accedeixi a una secció crítica del codi al mateix temps.

Conceptes Clau

  1. Mutex: Un objecte que permet bloquejar i desbloquejar l'accés a una secció crítica del codi.
  2. Condicions de Carrera: Situacions on dos o més goroutines accedeixen a dades compartides simultàniament, produint resultats inesperats.
  3. Secció Crítica: Part del codi que accedeix a recursos compartits i que ha de ser executada exclusivament per un goroutine a la vegada.

Utilització de Mutexes en Go

Go proporciona el paquet sync que inclou el tipus Mutex. A continuació, veurem com utilitzar-lo.

Exemple Bàsic

package main

import (
	"fmt"
	"sync"
)

var (
	counter int
	mutex   sync.Mutex
)

func increment(wg *sync.WaitGroup) {
	defer wg.Done()
	mutex.Lock()
	counter++
	mutex.Unlock()
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go increment(&wg)
	}

	wg.Wait()
	fmt.Println("Final Counter:", counter)
}

Explicació del Codi

  1. Declaració del Mutex: Declarem una variable mutex de tipus sync.Mutex.
  2. Bloqueig i Desbloqueig: Utilitzem mutex.Lock() per bloquejar l'accés a la secció crítica i mutex.Unlock() per desbloquejar-lo.
  3. WaitGroup: Utilitzem sync.WaitGroup per esperar que tots els goroutines acabin abans de continuar.

Exercici Pràctic

Objectiu: Implementar un programa que utilitzi mutexes per sincronitzar l'accés a un mapa compartit.

Instruccions

  1. Crea un mapa compartit per emmagatzemar valors.
  2. Utilitza un mutex per sincronitzar l'accés al mapa.
  3. Crea diversos goroutines que afegeixin valors al mapa.
  4. Assegura't que el programa imprimeixi el contingut final del mapa correctament.

Solució

package main

import (
	"fmt"
	"sync"
)

var (
	sharedMap = make(map[int]int)
	mutex     sync.Mutex
)

func addValue(key, value int, wg *sync.WaitGroup) {
	defer wg.Done()
	mutex.Lock()
	sharedMap[key] = value
	mutex.Unlock()
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go addValue(i, i*10, &wg)
	}

	wg.Wait()
	mutex.Lock()
	for k, v := range sharedMap {
		fmt.Printf("Key: %d, Value: %d\n", k, v)
	}
	mutex.Unlock()
}

Errors Comuns i Consells

  1. Oblidar Desbloquejar el Mutex: Assegura't de desbloquejar el mutex després de la secció crítica. Utilitza defer per garantir que el desbloqueig es faci fins i tot si hi ha un error.
  2. Bloqueig Innecessari: Evita bloquejar el mutex durant operacions que no necessiten sincronització.
  3. Condicions de Carrera: Utilitza eines com go run -race per detectar condicions de carrera durant el desenvolupament.

Resum

En aquesta secció, hem après com utilitzar mutexes per sincronitzar l'accés a recursos compartits en programes concurrents en Go. Hem vist un exemple pràctic i hem realitzat un exercici per reforçar els conceptes apresos. Els mutexes són una eina poderosa per evitar condicions de carrera i assegurar la consistència de les dades en entorns concurrents.

© Copyright 2024. Tots els drets reservats