Sobes.tech
Middle

Qu'est-ce qu'un mutex, quels types de mutex existent et comment les utiliser?

sobes.tech IA

Réponse de l'IA

Un mutex (de l'anglais MUTual EXclusion) est une primitive de synchronisation utilisée pour garantir un accès exclusif à une ressource partagée entre goroutines concurrentes. Il garantit qu'à tout moment, seule une goroutine peut posséder le mutex et accéder aux données protégées.

Dans Go, le package sync fournit deux principaux types de mutex:

  • sync.Mutex: Mutex standard. Fournit les méthodes Lock() et Unlock(). Si le mutex est déjà verrouillé, l'appel à Lock() bloque la goroutine en cours jusqu'à ce qu'il soit libéré. Unlock() libère le mutex.

    var mu sync.Mutex
    var counter int
    
    func increment() {
        mu.Lock() // Verrouille l'accès à counter
        counter++
        mu.Unlock() // Déverrouille l'accès
    }
    
  • sync.RWMutex: Mutex pour lecture/écriture. Permet à plusieurs goroutines de lire simultanément la ressource protégée, mais une seule peut écrire. Fournit les méthodes Lock(), Unlock() (pour l'écriture), RLock() et RUnlock() (pour la lecture).

    var rwMu sync.RWMutex
    var data []int
    
    func readData() {
        rwMu.RLock() // Verrouille pour la lecture
        // Lecture de data
        fmt.Println(data)
        rwMu.RUnlock() // Déverrouille la lecture
    }
    
    func writeData(val int) {
        rwMu.Lock() // Verrouille pour l'écriture
        // Écriture dans data
        data = append(data, val)
        rwMu.Unlock() // Déverrouille l'écriture
    }
    

L'utilisation de mutex est nécessaire pour prévenir les conditions de course (race conditions), lorsque plusieurs goroutines tentent de modifier les mêmes données simultanément, ce qui conduit à des résultats imprévisibles.

Règles d'utilisation:

  1. Appeler Lock() avant d'accéder à la ressource protégée.
  2. Appeler Unlock() après avoir terminé l'accès. Il est recommandé d'utiliser defer mu.Unlock() pour garantir la libération même en cas de panic.
  3. Ne pas tenter de verrouiller un mutex déjà verrouillé depuis la même goroutine (cela peut entraîner un deadlock).
  4. Ne pas tenter de déverrouiller un mutex non verrouillé.
  5. Lors de l'utilisation de RWMutex, utiliser RLock/RUnlock pour les opérations de lecture et Lock/Unlock pour les opérations d'écriture.
  6. Les mutex ne doivent pas être copiés après leur première utilisation. Transmettez-les par référence ou pointeur.

Exemple d'utilisation de defer:

func safeIncrement() {
    mu.Lock()
    defer mu.Unlock() // Garantit la libération
    counter++
}