


Qu'est-ce qui fait que ma goroutine reste bloquée dans le code mutex suivant ?
Feb 13, 2024 pm 06:57 PML'é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.
Contenu de la question
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
Solution
mylock peut verrouiller les mutex globaux et individuels. Cela rend le déverrouillage impossible dans certains cas :
- goroutine 1 appelle mylock(2). Cela provoque le verrouillage du verrou unique l2 comme prévu.
- goroutine 2 appelle mylock(2). Il acquiert le verrou global puis bloque en attendant que l2 soit libéré. Pendant l'attente, le verrouillage global continue d'être maintenu.
- goroutine 1 appelle myunlock(2). Il est bloqué en attendant que le verrou global (détenu par la goroutine 2) soit libéré. C'est une impasse.
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!

Article chaud

Outils chauds Tags

Article chaud

Tags d'article chaud

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

GO Language Pack Import: Quelle est la différence entre le soulignement et sans soulignement?

Comment mettre en œuvre le transfert d'informations à court terme entre les pages du cadre Beego?

Comment écrire des objets et des talons simulés pour les tests en Go?

Comment puis-je utiliser des outils de traçage pour comprendre le flux d'exécution de mes applications GO?

Comment rédigez-vous des tests unitaires en Go?

Comment convertir la liste des résultats de la requête MySQL en une tranche de structure personnalisée dans le langage Go?

Comment écrire des fichiers dans GO Language de manière pratique?

Comment puis-je définir des contraintes de type personnalisé pour les génériques en Go?
