补充翻译关于互斥锁不可重入性的解释

This commit is contained in:
lixiaojun629 2019-04-05 20:23:31 +08:00 committed by GitHub
parent 5d53b00aa8
commit 023ae210fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -102,7 +102,7 @@ func Withdraw(amount int) bool {
上面这个例子中Deposit会调用mu.Lock()第二次去获取互斥锁但因为mutex已经锁上了而无法被重入译注go里没有重入锁关于重入锁的概念请参考java——也就是说没法对一个已经锁上的mutex来再次上锁——这会导致程序死锁没法继续执行下去Withdraw会永远阻塞下去。 上面这个例子中Deposit会调用mu.Lock()第二次去获取互斥锁但因为mutex已经锁上了而无法被重入译注go里没有重入锁关于重入锁的概念请参考java——也就是说没法对一个已经锁上的mutex来再次上锁——这会导致程序死锁没法继续执行下去Withdraw会永远阻塞下去。
关于Go的mutex不能重入这一点我们有很充分的理由。mutex的目的是确保共享变量在程序执行时的关键点上能够保证不变性。不变性的其中之一是“没有goroutine访问共享变量”但实际上这里对于mutex保护的变量来说不变性还包括其它方面。当一个goroutine获得了一个互斥锁时它会断定这种不变性能够被保持。在其获取并保持锁期间,可能会去更新共享变量,这样不变性只是短暂地被破坏。然而当其释放锁之后,它必须保证不变性已经恢复原样。尽管一个可以重入的mutex也可以保证没有其它的goroutine在访问共享变量这种方式没法保证这些变量额外的不变性。(译注:这段翻译有点晕。 关于Go的mutex不能重入这一点我们有很充分的理由。mutex的目的是确保共享变量在程序执行时的关键点上能够保证不变性。不变性的一层含义是“没有goroutine访问共享变量”但实际上这里对于mutex保护的变量来说不变性还包含更深层含义当一个goroutine获得了一个互斥锁时它能断定被互斥锁保护的变量正处于不变状态译注即没有其他代码块正在读写共享变量在其获取并保持锁期间,可能会去更新共享变量,这样不变性只是短暂地被破坏然而当其释放锁之后锁必须保证共享变量重获不变性并且多个goroutine按顺序访问共享变量。尽管一个可以重入的mutex也可以保证没有其它的goroutine在访问共享变量它不具备不变性更深层含义。(译注:[更详细的解释](https://stackoverflow.com/questions/14670979/recursive-locking-in-go/14671462#14671462)Russ Cox认为可重入锁是bug的温床是一个失败的设计
一个通用的解决方案是将一个函数分离为多个函数比如我们把Deposit分离成两个一个不导出的函数deposit这个函数假设锁总是会被保持并去做实际的操作另一个是导出的函数Deposit这个函数会调用deposit但在调用前会先去获取锁。同理我们可以将Withdraw也表示成这种形式 一个通用的解决方案是将一个函数分离为多个函数比如我们把Deposit分离成两个一个不导出的函数deposit这个函数假设锁总是会被保持并去做实际的操作另一个是导出的函数Deposit这个函数会调用deposit但在调用前会先去获取锁。同理我们可以将Withdraw也表示成这种形式