WaitGroup.Wait()在这种情况下是否意味着内存屏障?

huangapple go评论85阅读模式
英文:

Does WaitGroup.Wait() imply memory barrier in this case?

问题

var condition bool
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(item) {
if meetsCondition(item) {
condition = true
}
wg.Done()
}(item)
}
wg.Wait()
// 在这里检查 condition 是否安全?

这个问题在旧的 Go 论坛上有讨论,链接在这里:
https://groups.google.com/forum/#!topic/golang-nuts/5oHzhzXCcmM 那里的答案是,是安全的。然后讨论转向了原子操作的使用等等,这不是我要问的问题。

在规范中甚至没有提到 WaitGroup,并且它的文档中说 WaitGroup.Wait: "Wait 会阻塞直到 WaitGroup 计数器为零。" 这并没有建立任何先行发生关系(或者有吗?)。

这是否意味着第一个答案 "在 wg.Wait 返回后检查 condition 是安全的" 是非官方的?如果它是官方的,我错过了什么原因?如果你回答的话,非常感谢。

更新:
这是在 @peterSO 和 @ravi 的回答之后的更新。谢谢。

显然,如果你选择的项目数量大于 1,就可能存在竞争条件。提示:condition 只能设置为 true。尽管如此,我还是有同样的问题。

而且,我应该声明:

  1. 底层架构只能是 x86、x64 或 ARM
  2. 项目数量可以是 1

更新 2
我为项目数量等于 1 的情况创建了一个后续问题,链接在这里:
https://stackoverflow.com/questions/45907588/can-you-make-this-incorrectly-synchronized-test-fail

英文:
var condition bool
var wg sync.WaitGroup
for _, item := range items {
	wg.Add(1)
	go func(item) {
		if meetsCondition(item) {
			condition = true
		}
		wg.Done()
	}(item)
}
wg.Wait()
// is it safe to check condition here?

There is a discussion of this question at the old go forum here:
https://groups.google.com/forum/#!topic/golang-nuts/5oHzhzXCcmM The answer there was yes, it is safe. Then the discussion digress to use of atomic, etc., which is not what I want to ask about.

There is not even one mention of WaitGroup in the spec and it's documentation is saying WaitGroup.Wait: "Wait blocks until the WaitGroup counter is zero." which does
not set any happens-before relationship (or does it?).

Does it mean that the first answer "It is safe to check condition after wg.Wait returns" is unofficial? If it's official what are the reasons for it I am missing? Thanks alot if you answer.

Update:
This is update after @peterSO's @ravi's answers. Thanks.

Well, obviously there can be a race condition if you choose number of items > 1. Hint: condition can be set only to true. Still, I have the same question.

And probably, I should have stated that:

  1. underlying architectures can be only x86, x64 or ARM
  2. number of items can be 1

Update 2
I created followup question for the case when number of items == 1 here:
https://stackoverflow.com/questions/45907588/can-you-make-this-incorrectly-synchronized-test-fail

答案1

得分: 3

是的,wg.Wait()wg.Done()之间存在happens-before关系。出于某种原因,这个简单的事实在文档或Go MM #7948中没有提到。感谢Ian Lance Taylor对此进行了澄清 golang-nuts/5oHzhzXCcmM。关于竞态条件,你可以在同一讨论线程中阅读更多信息。

有点令人失望的是,在一个自称并发的语言中,人们必须依赖于一个“好的字眼”来完成基本的事情(正确的)。

英文:

Yes. There is happens-before relationship between wg.Wait() and wg.Done(). This simple fact is for whatever reason not mentioned in doc or go MM #7948. Thanks Ian Lance Taylor for clarifying it golang-nuts/5oHzhzXCcmM. About the race condition you can read more in the same thread.

A bit disappointing that in a language that calls itself concurrent one has to rely on a 'good word' to do the basic stuff (right).

答案2

得分: 2

好的,以下是翻译好的内容:

嗯,检查wg.Wait()之后的condition是绝对安全的,但是你应该使用互斥锁来保护condition,以避免多个Go协程同时对其进行"写入"。这就是为什么@peterSO在他的代码中的第20行设置condition = true时会遇到竞争条件的原因,因为多个Go协程同时尝试设置condition。这里有一个示例https://play.golang.org/p/o3v6s_2qsY,其中包含了20,000个Go协程。

作为最佳实践,我建议在Go协程函数的开头添加defer wg.Done(),这样即使在其中有返回语句,wg.Done()仍然会被调用。

英文:

Well, it is absolutely safe to check condition after wg.Wait(), but you should protect condition with a mutex to avoid it being "written to" simultaneously by multiple go routines. That's why @peterSO is hitting a race condition b'cos at line 20 in his code which is setting condition = true multiple go routines are trying to set condition at the same time. Here's a sample https://play.golang.org/p/o3v6s_2qsY with 20k go rountines.

As a best practice I recommend, one adds defer wg.Done() right in the beginning of the go routine function, so that even if there are return statements in between, wg.Done() still gets called.

huangapple
  • 本文由 发表于 2017年8月26日 19:46:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/45894997.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定