跨go例程共享内存
Go中的以下测试失败:跨go例程共享内存,go,concurrency,shared-memory,goroutine,Go,Concurrency,Shared Memory,Goroutine,Go中的以下测试失败: type A struct { b bool } func TestWG(t *testing.T) { var wg sync.WaitGroup a := update(&wg) wg.Wait() if !a.b { t.Errorf("error") } } // Does not work func update(group *sync.WaitGroup) A {
type A struct {
b bool
}
func TestWG(t *testing.T) {
var wg sync.WaitGroup
a := update(&wg)
wg.Wait()
if !a.b {
t.Errorf("error")
}
}
// Does not work
func update(group *sync.WaitGroup) A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
return a
}
起初,我认为这可能是由于waitGroup.Done()
中没有屏障造成的,这可能解释了为什么将update
更改为
// works
func update(group *sync.WaitGroup) A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
time.Sleep(1*time.Second)
return a
}
工作。但是,将返回类型更改为指针
也可以使其工作
// works
func update(group *sync.WaitGroup) *A {
a := A{
b : false,
}
group.Add(1)
go func() {
a.b = true
group.Done()
}()
return &a
}
有人能告诉我这里发生了什么吗?您的第一个示例是数据竞赛 您返回一个需要读取它的
a
,而一个并发goroutine(您刚刚启动)在不同步的情况下写入它。所以输出是未定义的<代码>开始测试-比赛也证实了这一点
添加睡眠时也会发生同样的情况:数据竞争仍然存在(不是同步工具),因此结果仍然未定义<代码>开始测试-比赛再次确认这一点
当您将返回类型更改为指针时,您只需返回指向
a
的指针,该指针不涉及读取a
的值,并且启动的goroutine不会修改指针,只修改指向的值。调用方TestWG()
使用waitgroup正确地等待它完成,因此这里不会发生数据竞争。您的第一个示例有一个数据竞争
您返回一个需要读取它的a
,而一个并发goroutine(您刚刚启动)在不同步的情况下写入它。所以输出是未定义的<代码>开始测试-比赛也证实了这一点
添加睡眠时也会发生同样的情况:数据竞争仍然存在(不是同步工具),因此结果仍然未定义<代码>开始测试-比赛再次确认这一点
当您将返回类型更改为指针时,您只需返回指向
a
的指针,该指针不涉及读取a
的值,并且启动的goroutine不会修改指针,只修改指向的值。调用方TestWG()
使用waitgroup正确地等待,直到它完成,所以这里不会发生数据争用。如果我只在wg.Wait()之后读取值,为什么会是数据争用呢?@user3301880就是这样:返回a
涉及读取它,这发生在调用wg.Wait()
之前,它与另一个goroutine同时更新它。但是当您返回&a
时,并不需要阅读a
,这会有所帮助。非常感谢。如果我只在wg.Wait()之后读取值,为什么这是一场数据竞赛?@user3301880就是这样:返回a
涉及读取它,这发生在调用wg.Wait()
之前,它与另一个goroutine更新它同时发生。但是当您返回&a
时,并不需要阅读a
,这会有所帮助。非常感谢你。