php小編新一在這裡給大家解答一個常見問題:「是什麼導致我的goroutine在以下互斥體程式碼中陷入僵局?」在並發程式設計中,使用互斥鎖(Mutex)是常見的解決共享資源競爭的方法之一。然而,如果程式碼中存在一些問題,可能會導致goroutine陷入僵局,無法繼續執行。接下來,我們將詳細討論可能導致該問題的原因,並給出解決方案。
我試著保存一張鑰匙圖,每個鑰匙都有單獨的鎖。 在為特定密鑰建立鎖定時,我使用全域互斥體寫入映射。
完成為鑰匙建立鎖定後,我將使用新鎖並在完成工作後釋放。 目前我正在嘗試修改單一密鑰以測試我的程式碼。
這是程式碼:
// 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) }
我不確定為什麼它無法取得鎖。 遊樂場連結:https://go.dev/play/p/-co0xaxpuy0
mylock 可鎖定全域互斥鎖和單一互斥鎖。這使得在某些情況下無法解鎖:
要解決此問題,請在持有全域鎖時返回各個鎖,而不是(取消)鎖定它們。 myunlock 功能變得不必要:
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) }
為了提高效能,您可以先檢查單一鎖定是否存在,同時僅持有全域讀取鎖定(請注意,這會變更 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 }
以上是是什麼導致我的 goroutine 在以下互斥體程式碼中陷入僵局?的詳細內容。更多資訊請關注PHP中文網其他相關文章!