跨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 {

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 {
    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
,这会有所帮助。非常感谢你。