乐趣区

关于golang:Go-Quiz-从Go面试题看锁的注意事项

背景

Google 工程师 Valentin Deleplace 出了 2 道对于锁的题目,拿进去和大家分享下。

题目 1

// quiz_lock1.go
package main

import (
    "fmt"
    "sync"
)

func main() {
    var m sync.Mutex
    fmt.Print("1,")
    m.Lock()
    m.Lock()
    m.Unlock()
    fmt.Println("2")
}
  • A: 1, 2
  • B: 1,
  • C: 1, fatal error:......
  • D: 编译报错

题目 2

// quiz_lock2.go
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var m sync.Mutex
    fmt.Print("1,")
    m.Lock()

    go func() {time.Sleep(200 * time.Millisecond)
        m.Unlock()}()

    m.Lock()
    fmt.Println("2")
}
  • A: 1, 2
  • B: 1,
  • C: 1, fatal error:......
  • D: 编译报错

解析

Go 语言里的 sync.Mutex 和 sync.RWMutex 都是不可重入的,Go 语言里没有可重入锁(也叫递归锁)。

如果 mutex 没有开释,在同一个 goroutine 就不能对这个 mutex 加 2 次锁,否则第 2 次加锁就会阻塞,如果没有其它 goroutine 去开释这个 mutex,就会导致死锁,呈现 runtime error: fatal error: all goroutines are asleep - deadlock!

同时,sync.Mutex 和 sync.RWMutex 容许一个 goroutine 对其加锁,其它 goroutine 对其解锁,不要求加锁和解锁在同一个 goroutine 里。

所以第一道题目的答案是C,第二道题目的答案是A

思考题

// quiz_lock3.go

package main

import (
    "fmt"
    "sync"
)

var a sync.Mutex

func main() {a.Lock()
    fmt.Print("1,")
    a.Unlock()
    fmt.Print("2,")
    a.Unlock()
    fmt.Println("3")
}
  • A: 1, 2, 3
  • B: 1, 2, fatal error:......
  • C: 1, 2
  • D: 编译报错

想晓得答案的能够给公众号发送音讯 mutex 获取答案。

总结

Go 语言里的锁和 C ++,Java 里的不太一样,给大家总结了以下注意事项

  • Go 的锁是不可重入的,没有递归锁
  • 容许一个 goroutine 加锁,另一个 goroutine 解锁,不要求加锁和解锁在同一个 goroutine 里
  • sync.Mutex 的零值是没有加锁的 Mutex,sync.RWMutex 的零值是没有加锁的 RWMutex
  • 更多细节能够参考 References 里 Mutex 和 RWMutex 的官网阐明

开源地址

文章和示例代码开源在 GitHub: Go 语言高级、中级和高级教程。

公众号:coding 进阶。关注公众号能够获取最新 Go 面试题和技术栈。

集体网站:Jincheng’s Blog。

知乎:无忌。

References

  • https://github.com/jincheng9/…
  • https://twitter.com/val_delep…
  • https://twitter.com/val_delep…
  • https://pkg.go.dev/sync@go1.1…
  • https://pkg.go.dev/sync@go1.1…
退出移动版