忘记解锁mutex的后果

这节,您会看到如果您忘记解锁 sync.Mutex 的后果。您将使用 forgetMutex.go 代码来做这个,把它分两部分来介绍。

forgetMutex.go 第一段代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var m sync.Mutex
  7. func function() {
  8. m.Lock()
  9. fmt.Println("Locked!")
  10. }

这个程序的所有问题是由于开发者忘记释放 m sync.Mutex 互斥体的锁导致的。然而,如果您的程序只调用 function() 一次,那一切正常!

forgetMutex.go 的第二段如下:

  1. func main() {
  2. var w sync.WaitGroup
  3. go func() {
  4. defer w.Done()
  5. function()
  6. }()
  7. w.Add(1)
  8. go func() {
  9. defer w.Done()
  10. function()
  11. }()
  12. w.Add(1)
  13. w.Wait()
  14. }

main() 函数没有任何问题,它创建两个 goroutines 并等它们完成。

执行 forgetMutex.go 产生如下输出:

  1. $go run forgetMutex.go
  2. Locked!
  3. fatal error: all goroutines are asleep - deadlock!
  4. goroutine 1 [semacquire]:
  5. sync.runtime_Semacquire(0xc42001209c)
  6. /usr/local/Cellar/go/1.9.4/libexec/src/runtime/sema.go:56 +0x39
  7. sync.(*WaitGroup).Wait(0xc420012090)
  8. /usr/local/Cellar/go/1.9.4/libexec/src/sync/waitgroup.go:131 +0x72 main.main()
  9. /Users/mtsouk/forgetMutex.go:30 +0xb6
  10. goroutine 5 [semacquire]:
  11. sync.runtime_SemacquireMutex(0x115c6fc, 0x0)
  12. /usr/local/Cellar/go/1.9.4/libexec/src/runtime/sema.go:71 +0x3d
  13. sync.(*Mutex).Lock(0x115c6f8)
  14. /usr/local/Cellar/go/1.9.4/libexec/src/sync/mutex.go:134 +0xee main.function()
  15. /Users/mtsouk/forgetMutex.go:11 +0x2d main.main.func1(0xc420012090)
  16. /Users/mtsouk/forgetMutex.go:20 +0x48 created by main.main
  17. /Users/mtsouk/forgetMutex.go:18 +0x58 exit status 2

所以,忘记解锁 sync.Mutex 互斥体会产生崩溃即使是最简单的程序。这同样适用于您将在下一节中使用的 sync.RWMutex 类型的互斥锁。