我们应该在goroutine中同步变量分配吗?

时间:2019-03-19 09:26:26

标签: go concurrency synchronization locking

假设我声明了两个映射,并希望将其分配给错误组中的两个不同的goroutine。我不执行任何读/写操作。 我应该使用lock保护分配操作还是可以忽略它?

UPD3:在Java Concurrency In Practice Brian Goetz's第I部分第3章Shared Objects中,提到:

  

锁定不仅涉及互斥;这也是记忆   能见度。为确保所有线程看到最新值   共享的可变变量,读写线程必须   同步公用锁。

var (
    mu     sync.Mutex
    one    map[string]struct{}
    two    map[string]struct{}
)
g, gctx := errgroup.WithContext(ctx)
g.Go(func() error {
    resp, err := invokeFirstService(gctx, request)
    if err != nil {
        return err
    }
    mu.Lock()
    one = resp.One
    mu.Unlock()
    return nil
})

g.Go(func() error {
    resp, err := invokeSecondService(gctx, request)
    if err != nil {
        return err
    }
    mu.Lock()
    two = resp.Two
    mu.Unlock()
    return nil
})
if err := g.Wait(); err != nil {
    return err
}
// UPD3: added lock and unlock section
m.Lock()
defer m.Unlock()
performAction(one, two)

UPD:添加了有关变量的更多上下文

UPD2:我有什么疑问:我们有3个goroutines-父类和错误组中的2个。无法保证在errgroup goroutine完成后,我们的父goroutine共享内​​存会获得最后更新,直到我们用内存屏障包装对共享内存的访问为止

2 个答案:

答案 0 :(得分:3)

Group.Wait()阻塞,直到返回了来自Group.Go()方法的所有函数调用为止,因此这是一个同步点。这样可确保\agent_diag在对performAction(one, two)one的任何写操作完成之前不会启动,因此在您的示例中,互斥锁是不必要的。

two

如果您在写它们的goroutine同时运行时从其他goroutine访问g, gctx := errgroup.WithContext(ctx) g.Go(func() error { // ... one = resp.One return nil }) g.Go(func() error { // ... two = resp.Two return nil }) if err := g.Wait(); err != nil { return err } // Here you can access one and two safely: performAction(one, two) one,则是的,您需要锁定它们,例如:

two

还要注意,在上面的示例中,您可以使用sync.RWMutex,在读取它们的goroutine中,RWMutex.RLock()RWMutex.RUnlock()也足够。

答案 1 :(得分:0)

在这种情况下,只有一个goroutine可以访问地图。我认为您不需要锁。