在学习go的锁机制的时候,他有互斥锁和读写锁【读锁,写锁】三种锁。我对他们的理解是:
- 对资源加互斥锁,那么在解锁之前就不能对他加其他任何的锁。
- 对资源加读锁,那么可以对他加其他读锁,但是不能加写锁
- 对资源加写锁,那么解锁之前不能对他加其他写锁和读锁
然后我对他们进行验证,具体有9种情况:
var rw sync.RWMutex //读写锁
var l sync.Mutex //互斥锁
func main() {
readAndRead()
time.Sleep(3 * time.Second)
}
第一种:互斥锁嵌套写锁,代码正常
func readAndRead() {
l.Lock()
rw.Lock()
fmt.Println("11111111")
rw.Unlock()
fmt.Println("22222222")
l.Unlock()
}
第二种:互斥锁嵌套读锁,代码正常
func readAndRead() {
l.Lock()
rw.RLock()
fmt.Println("11111111")
rw.RUnlock()
fmt.Println("22222222")
l.Unlock()
}
第三种:互斥锁嵌套互斥锁,代码报:fatal error: all goroutines are asleep - deadlock!
func readAndRead() {
l.Lock()
l.Lock()
fmt.Println("11111111")
l.Unlock()
fmt.Println("22222222")
l.Unlock()
}
第四种:写锁嵌套互斥锁,代码正常
func readAndRead() {
rw.Lock()
l.Lock()
fmt.Println("11111111")
l.Unlock()
fmt.Println("22222222")
rw.Unlock()
}
第五种:写锁嵌套写锁,代码报:fatal error: all goroutines are asleep - deadlock!
func readAndRead() {
rw.Lock()
rw.Lock()
fmt.Println("11111111")
rw.Unlock()
fmt.Println("22222222")
rw.Unlock()
}
第六种:写锁嵌套读锁,代码报:fatal error: all goroutines are asleep - deadlock!
func readAndRead() {
rw.Lock()
rw.RLock()
fmt.Println("11111111")
rw.RUnlock()
fmt.Println("22222222")
rw.Unlock()
}
第七种:读锁嵌套互斥锁,代码正常
func readAndRead() {
rw.RLock()
l.Lock()
fmt.Println("11111111")
l.Unlock()
fmt.Println("22222222")
rw.RUnlock()
}
第八种:读锁嵌套读锁,代码正常
func readAndRead() {
rw.RLock()
rw.RLock()
fmt.Println("11111111")
rw.RUnlock()
fmt.Println("22222222")
rw.RUnlock()
}
第九种:读锁嵌套写锁,代码报:fatal error: all goroutines are asleep - deadlock!
func readAndRead() {
rw.RLock()
rw.Lock()
fmt.Println("11111111")
rw.Unlock()
fmt.Println("22222222")
rw.RUnlock()
}
通过这9种,我发现我上面理解的3点好像对不上,比如:第一点互斥锁不能与其他锁共存,但是第一种和第二种情况代码为什么正常运行?还有就是为什么第七种读锁里面有互斥锁也能正常运行?
是不是我理解的3点不够全面?希望大伙帮忙解答一下,谢谢!!
互斥都是基于同一把锁的。两把不同的锁之间是没有任何关系的。所以你代码里的
l
跟rw
是没有任何关系的,它们各自加锁是否成功跟另一把锁的状态完全无关,只跟自己的状态有关。如果一定要与上面的话对应,也可以认为“资源”就是锁本身。锁保护了什么是程序员的事,锁并不关心,也不知道。所以
l.Lock()
跟rw.Lock()
是在对不同的资源加锁。它们之间是无关的。锁有互斥锁跟读写锁两种类型。对互斥锁,你只能对他加互斥锁,无法加读锁跟写锁。
对读写锁,可以对它加读锁或者写锁。
去掉你代码里
l
跟rw
嵌套的所有例子,应该就与上面的叙述一致了。