跨 Go 例程的共享内存

Shared memory across go routines

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
}

有效。但是然后将 return 类型更改为 pointer 也可以使它工作

// works
func update(group *sync.WaitGroup) *A {
    a := A{
        b : false,
    }
    group.Add(1)
    go func() {
        a.b = true
        group.Done()
    }()
    return &a
}

谁能告诉我这里发生了什么?

您的第一个示例存在数据竞争!

你 return a 需要读取它,并发 goroutine(你刚刚启动)在没有同步的情况下写入它。所以输出是未定义的! go test -race也证实了这一点。

添加睡眠时,情况相同:数据竞争仍然存在(time.Sleep() 不是 同步工具),所以结果仍然未定义! go test -race 再次确认这一点。

当您将 return 类型更改为指针时,您只是 return 一个指向 a 的指针,它不涉及读取 a 的值,并且启动的 goroutine 不修改指针,只修改指向的值。并且调用者 TestWG() 正确地等待直到它使用等待组完成,所以这里没有数据竞争发生。