From 023ae210fc9795a3c98ea18c32f38a24f5c484d9 Mon Sep 17 00:00:00 2001 From: lixiaojun629 Date: Fri, 5 Apr 2019 20:23:31 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E7=BF=BB=E8=AF=91=E5=85=B3?= =?UTF-8?q?=E4=BA=8E=E4=BA=92=E6=96=A5=E9=94=81=E4=B8=8D=E5=8F=AF=E9=87=8D?= =?UTF-8?q?=E5=85=A5=E6=80=A7=E7=9A=84=E8=A7=A3=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch9/ch9-02.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch9/ch9-02.md b/ch9/ch9-02.md index 1f8aa98..829e547 100644 --- a/ch9/ch9-02.md +++ b/ch9/ch9-02.md @@ -102,7 +102,7 @@ func Withdraw(amount int) bool { 上面这个例子中,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也表示成这种形式: