使用WaitGroup从不同的go例程中阻止当前变量写入堆栈变量是否安全?

有各种各样的任务执行器,它们具有不同的属性,其中一些仅支持非阻塞调用。因此,我在想,是否需要使用互斥锁/通道来安全地将任务结果传递给调用go-routine,还是WaitGroup是否足够简单?

为简单起见,以及问题的特殊性,举一个非常幼稚的任务执行器启动函数直接作为go例程的示例:

func TestRace(t *testing.T) {
    var wg sync.WaitGroup

    a,b := 1,2

    wg.Add(1)

    // this func would be passed to real executor
    go func() {
        a,b = a+1,b+1
        wg.Done()
    }()

    wg.Wait()

    assert.Equal(t,a,2)
    assert.Equal(t,b,3)
}

在我的计算机上,使用-race选项执行上述测试没有失败。但是,这足够保证吗?如果在不同的CPU内核,CPU内核块(AMD CCX)或多插槽设置的不同CPU上执行例程,该怎么办?

因此,问题是,我可以使用WaitGroup为非阻塞执行程序提供同步(阻塞和返回值)吗?

yinghuochong512 回答:使用WaitGroup从不同的go例程中阻止当前变量写入堆栈变量是否安全?

JimB也许应该提供答案,但是我将从his开始的comments this one复制它:

  

此处的WaitGroup是为了确保a,b = a+1,b+1已执行,因此没有理由假定它没有执行。

[和]

  

[T]他保证您已经被go内存模型所布局,该模型已经有详细的文档[here]。 [具体来说,示例中wg.Done()wg.Wait()的组合足以保证对两个变量ab的非恶意访问。]

只要存在此问题,也可以复制Adrian's comment

  

正如@JimB所指出的,如果goroutines之间共享一个值,则该值不能进行堆栈分配,因此该问题没有任何意义(请参阅How are Go closures layed out in memory?)。 WaitGroup正常工作。

关闭变量是堆分配的事实是实现细节:将来可能不正确。但是sync.WaitGroup保证 在将来仍然适用,即使将来某个聪明的Go编译器能够将这些变量保留在某个堆栈中。

(“哪个堆栈?”完全是另一个问题,但是假设的未来聪明的Go编译器需要回答。WaitGroup和内存模型提供了规则。)

本文链接:https://www.f2er.com/3065980.html

大家都在问