L'éditeur PHP Xinyi est là pour répondre à une question courante : "Qu'est-ce qui fait que ma goroutine reste bloquée dans le code mutex suivant ? En programmation simultanée, l'utilisation de verrous mutex (Mutex) est courante. L'une des façons de résoudre concurrence pour les ressources partagées. Cependant, s'il y a des problèmes dans le code, la goroutine peut se retrouver bloquée et incapable de poursuivre son exécution. Ensuite, nous discuterons en détail des causes possibles de ce problème et proposerons des solutions.
J'essaie d'enregistrer une carte de clés, chaque clé a une serrure séparée. Lors de la création d'un verrou pour une clé spécifique, j'utilise un mutex global pour écrire sur la carte.
Une fois la création du verrou pour la clé terminée, j'utiliserai le nouveau verrou et je le libérerai une fois le travail terminé. Actuellement, j'essaie de modifier une seule clé pour tester mon code.
Voici le code :
// You can edit this code! // Click here and start typing. package main import ( "fmt" "sync" "time" ) var count int var globalMutex *sync.RWMutex var mutexes map[int]*sync.Mutex func MyLock(index int) { fmt.Println("Aquiring Lock") globalMutex.Lock() defer globalMutex.Unlock() count++ if mutexes == nil { mutexes = make(map[int]*sync.Mutex) } if _, ok := mutexes[index]; !ok { mutexes[index] = &sync.Mutex{} } fmt.Println("Aquiring 2nd Lock") mutexes[index].Lock() fmt.Println("Aquired Lock") } func MyUnlock(index int) { globalMutex.Lock() defer globalMutex.Unlock() mutexes[index].Unlock() } func main() { var wg sync.WaitGroup globalMutex = &sync.RWMutex{} wg.Add(500) for i := 0; i < 500; i++ { go func(i int) { defer wg.Done() MyLock(2) time.Sleep(1 * time.Second) fmt.Println(i) MyUnlock(2) }(i) } wg.Wait() fmt.Println(mutexes) fmt.Println(count) }
Je ne sais pas pourquoi il ne peut pas acquérir le verrou. Lien Playground : https://go.dev/play/p/-co0xaxpuy0
mylock peut verrouiller les mutex globaux et individuels. Cela rend le déverrouillage impossible dans certains cas :
Pour résoudre ce problème, remettez les verrous individuels tout en maintenant le verrou global au lieu de les (dé)verrouiller. La fonction myunlock devient inutile :
func mylock(index int) *sync.mutex { globalmutex.lock() defer globalmutex.unlock() count++ if mutexes == nil { mutexes = make(map[int]*sync.mutex) } mu := mutexes[index] if mu == nil { mu = &sync.mutex{} mutexes[index] = mu } return mu } func main() { var wg sync.waitgroup globalmutex = &sync.rwmutex{} wg.add(500) for i := 0; i < 500; i++ { go func(i int) { defer wg.done() mu := mylock(2) mu.lock() defer mu.unlock() time.sleep(1 * time.second) fmt.println(i) }(i) } wg.wait() fmt.println(mutexes) fmt.println(count) }
Pour améliorer les performances, vous pouvez d'abord vérifier si un seul verrou existe, tout en ne détenant qu'un verrou global en lecture (notez que cela change ce que représente count
) :
func MyLock(index int) *sync.Mutex { globalMutex.RLock() mu := mutexes[index] globalMutex.RUnlock() if mu != nil { return mu } globalMutex.Lock() defer globalMutex.Unlock() count++ if mutexes == nil { mutexes = make(map[int]*sync.Mutex) } mu = mutexes[index] // have to check again because if mu == nil { // we briefly released globalMutex mu = &sync.Mutex{} mutexes[index] = mu } return mu }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!