go sync: clarify WaitGroup.Done() behaviour when the counter is zero

lpwwtiir  于 4个月前  发布在  Go
关注(0)|答案(7)|浏览(46)

我认为值得注意的是,如果计数器已经为零,WaitGroup.Done()会恐慌。目前可以从文档中推断出来,但不是非常明显。

bnlyeluc

bnlyeluc1#

你认为呢,@bcmills?

kwvwclae

kwvwclae2#

在Go中,恐慌是一种可恢复的操作,但对Done的剩余调用往往伴随着数据竞争(这是未定义的行为,而不是可恢复的错误)。因此,我认为将对Done的剩余调用定义为恐慌是一个错误,因为恐慌仅对Done调用的狭窄子集有定义行为。
另一方面,我们已经犯了对Add方法的错误,而Done()等同于Add(-1)

3lxsmp7m

3lxsmp7m3#

在调用公共WaitGroup方法时,WaitGroup的内存上是否存在任何数据竞争?如果没有,并且只是猜测Done的过度调用伴随着一些数据竞争,但不是WaitGroup本身,我认为这是对不描述Done()被多次调用后会发生什么情况的奇怪辩解。类似的论点可以应用于任何函数:在调用它之前,可能会存在数据竞争。
具有Java背景的开发人员,其中额外的CountDownLatch.countDown()调用是无操作的,可以不加思索地调用Done(),例如在循环中,认为额外的保护布尔变量是不必要的。

siv3szwd

siv3szwd4#

如果计数器变为负数,WaitGroup(#20687)中会发生溢出,从而破坏等待者计数:
https://github.com/golang/go/blob/go1.14.4/src/sync/waitgroup.go#L64
这并不是正式的数据竞争,但也不是可恢复的条件。你真的不希望在循环中无意识地调用Done,即使你recover了由此产生的恐慌。

k97glaaz

k97glaaz5#

最近,由于没有意识到Done在counter为负数时会恐慌,我编写了以下代码(基本上,我想在任何一个goroutine退出时立即ublock main)
https://play.golang.org/p/3f_9iOk7GEY
如果文档对Done的行为更清晰,就不会发生这种情况。

d4so4syb

d4so4syb6#

Done是一个Add(-1)的快捷方式。这个行为在Add文档中有解释。
也许Done的文档应该提到这个事实(它是一个Add(-1)的快捷方式)。

xwmevbvl

xwmevbvl7#

也许Done的文档应该提到这个事实(这是一个Add(-1)的快捷方式)。
@go101 是的,如果在文档中提到了这一点,当然可以。但除此之外,这还是一个实现细节,我不得不浏览代码来学习。(也不知道是否可以从一个版本发布到另一个版本)

相关问题