检测同一 goroutine 连续两次调用sync.Mutex.Lock()

Kev*_*rke 4 mutex locking go reentrancy

这段代码(单线程程序)永远不会工作:

func TestDoubleLockPanics(t *testing.T) {
    var mu sync.Mutex
    mu.Lock()
    mu.Lock()
}
Run Code Online (Sandbox Code Playgroud)

然而,当我运行这个测试时,并没有恐慌。竞争检测器不会打印出数据竞争。go vet不抱怨,没有日志消息,它只是永远阻塞。

(显然,我关心的实际代码并不是这么简单 - 我只是将其归结为本质。)

当持有锁的线程尝试重新获取相同的锁时,有什么方法可以让 Go 大声告诉我吗?

tor*_*rek 5

Go 的sync.Mutex对象不跟踪哪个 goroutine 锁定了它们。或者,换句话说,没有锁定线程:只有数据锁。

此外,正如上面的评论Unlock所说,您可以从锁定它们的 goroutine 之外的其他 goroutine 中解锁它们。因此,调用Lock两次实际上是有意义的。这是一个骨架示例:

func f() {
    mu.Lock()
    ... if this is not just an example, some code goes here ...
    // now wait for g() to call mu.Unlock()
    mu.Lock()
    fmt.Println("we got here, so g() must have done an unlock")
    mu.Unlock()
}

func g() {
    ... some code probably goes here too ...
    mu.Unlock() // allow f() to proceed
    ... more code, perhaps ...
}
Run Code Online (Sandbox Code Playgroud)

f在这种情况下,我们不希望在第二次调用中出现恐慌Lock

您可以构建自己的递归锁或其他技术,但由于每个 goroutine 的内部 ID 是隐藏的,因此非常棘手在Recursivelocking in Go答案的评论中有一个实现的链接,但我从未使用过它,甚至没有仔细研究过它。