我想写一个像https://github.com/im7mortal/kmutex一样的互斥锁。 ,但思路不同。只是将互斥锁存储在hashmap中。但我的代码中总是存在一些死锁。我如何找到错误?还是有更好的方法来编写 key 互斥体?
package kmutex
import (
"sync"
)
type keyMutex struct {
localLockMap map[string]*sync.Mutex
globalLock sync.Mutex
}
func NewKeyMutex() *keyMutex {
return &keyMutex{localLockMap: map[string]*sync.Mutex{}}
}
func (km *keyMutex) Lock(key string) {
km.globalLock.Lock()
wl, ok := km.localLockMap[key]
if !ok {
wl = &sync.Mutex{}
km.localLockMap[key] = wl
}
km.globalLock.Unlock()
wl.Lock()
}
func (km *keyMutex) Unlock(key string) {
km.globalLock.Lock()
wl, ok := km.localLockMap[key]
if !ok {
km.globalLock.Unlock()
return
}
delete(km.localLockMap, key)
km.globalLock.Unlock()
wl.Unlock()
}
下面是测试代码
func TestKeyMutex1(t *testing.T) {
keyMutex := kmutex.NewKeyMutex()
//var keyMutex sync.Mutex
var count = 0
var wg sync.WaitGroup
var num = 100
for i := 1; i <= num; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
keyMutex.Lock("a")
count += i
keyMutex.Unlock("a")
}(i)
}
wg.Wait()
println(count)
}
它总是有死锁。在我删除行 delete(km.localLockMap, key)
之后。死锁消失了!但是还是看不懂
最佳答案
问题确实是删除映射中的互斥量。
考虑在同一个条目(“a”
)中按以下顺序运行三个锁(当然是在多个 goroutine 中):
keyMutex.Lock("a") // lock1
keyMutex.Lock("a") // lock2
keyMutex.Lock("a") // lock3
keyMutex.Unlock("a") // unlock1
keyMutex.Unlock("a") // unlock2
keyMutex.Unlock("a") // unlock3
lock1
在map中创建一个mutex,然后lock2
和lock3
获取相同的mutex,阻塞在mutex的Lock上。 unlock1
找到互斥量,将其解锁并将其从映射中移除,解锁 lock2
(或 lock3
,但为了讨论起见,假设它是锁2
)。但是当 unlock2
或 unlock3
运行时,它在映射中发现没有互斥体,没有解锁任何东西,并保持 lock3
阻塞,因此出现死锁。
从映射中删除互斥量的行根本没有意义:互斥量是可重用的,在上下文中,只有对相同的条目使用相同的互斥量才是明智的。
关于go - 如何在无错误的情况下按键编写互斥锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55988340/