Golang的锁的理解

在学习go的锁机制的时候,他有互斥锁和读写锁【读锁,写锁】三种锁。我对他们的理解是:

  1. 对资源加互斥锁,那么在解锁之前就不能对他加其他任何的锁。
  2. 对资源加读锁,那么可以对他加其他读锁,但是不能加写锁
  3. 对资源加写锁,那么解锁之前不能对他加其他写锁和读锁

然后我对他们进行验证,具体有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点不够全面?希望大伙帮忙解答一下,谢谢!!

阅读 1.2k
2 个回答

互斥都是基于同一把锁的。两把不同的锁之间是没有任何关系的。所以你代码里的 lrw 是没有任何关系的,它们各自加锁是否成功跟另一把锁的状态完全无关,只跟自己的状态有关。

如果一定要与上面的话对应,也可以认为“资源”就是锁本身。锁保护了什么是程序员的事,锁并不关心,也不知道。所以 l.Lock()rw.Lock() 是在对不同的资源加锁。它们之间是无关的。

锁有互斥锁跟读写锁两种类型。对互斥锁,你只能对他加互斥锁,无法加读锁跟写锁。

对读写锁,可以对它加读锁或者写锁。

去掉你代码里 lrw 嵌套的所有例子,应该就与上面的叙述一致了。

新手上路,请多包涵

fete已经回答的很好了,我补充两点:
首先,你是否发现跑不通的case都存在重复加锁的现象?
其次,你只开了一个主协程去测试锁,测试用例未免太单薄了。建议多起几个goroutine尝试下。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题