10.5.1.1 忘记解锁mutex的后果

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

forgetMutex.go 第一段代码如下:

package main

import (
    "fmt"
    "sync"
)

var m sync.Mutex

func function() {
    m.Lock()
    fmt.Println("Locked!")
}

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

forgetMutex.go 的第二段如下:

func main() {
    var w sync.WaitGroup

    go func() {
        defer w.Done()
        function()
    }()
    w.Add(1)

    go func() {
        defer w.Done()
        function()
    }()
    w.Add(1)

    w.Wait()
}

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

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

$go run forgetMutex.go
Locked!
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc42001209c)
    /usr/local/Cellar/go/1.9.4/libexec/src/runtime/sema.go:56 +0x39
sync.(*WaitGroup).Wait(0xc420012090)
    /usr/local/Cellar/go/1.9.4/libexec/src/sync/waitgroup.go:131 +0x72 main.main()
    /Users/mtsouk/forgetMutex.go:30 +0xb6

goroutine 5 [semacquire]:
sync.runtime_SemacquireMutex(0x115c6fc, 0x0)
    /usr/local/Cellar/go/1.9.4/libexec/src/runtime/sema.go:71 +0x3d
sync.(*Mutex).Lock(0x115c6f8)
    /usr/local/Cellar/go/1.9.4/libexec/src/sync/mutex.go:134 +0xee main.function()
    /Users/mtsouk/forgetMutex.go:11 +0x2d main.main.func1(0xc420012090)
    /Users/mtsouk/forgetMutex.go:20 +0x48 created by main.main
    /Users/mtsouk/forgetMutex.go:18 +0x58 exit status 2

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

Last updated