同一结构中的多个互斥体?

Multiple mutexes in same struct?

我有一些关于 Go 的 sync.Mutexstruct 一起使用的相关问题。例如,如果我有这个 struct:

type something struct {
    aMux sync.Mutex
    a    map[string]interface{}

    bMux sync.Mutex
    b    int
}

... 在没有竞争条件的情况下同时锁定 aMux 和访问 a 时锁定 bMux 和访问 b 是否安全?

了解我正在访问指向结构的指针,并使用类似这样的方法同时 lock/unlock 互斥体可能也有帮助:

func (s *something) addA(k string, v interface{}) {
    (*s).aMux.Lock()
    (*s).a[k] = v
    (*s).aMux.Unlock()
}

func (s *something) addB(k string, v interface{}) {
    (*s).bMux.Lock()
    (*s).b++
    (*s).bMux.Unlock()
}

我的假设是这在理论上应该是安全的,因为您已经可以在结构中锁定互斥锁而无需访问它锁定的字段。 但是当像上面那样取消引用 struct 时,Go 是从 struct 复制所有值(使其不安全),还是仅 modify/retrieve 您指定的字段?

我非常希望将互斥量保留在同一个结构中,因为在我的代码中,我在同一个结构中有多个(最多六个)相关字段,我用互斥量分别锁定。 如果在同一个结构(对于相关字段)中有多个互斥体是安全的,但不推荐或不好的做法,为什么?什么是更好的结构?

在一个结构中拥有多个互斥量应该是安全的。请注意不要按值传递结构,因为互斥锁不是引用类型并且复制它们是错误的(有关详细信息,请参阅 this discussion)。

您不需要显式取消引用,Go 会为您完成:

func (s *something) addA(k string, v interface{}) {
    s.aMux.Lock()
    s.a[k] = v
    s.aMux.Unlock()
}

应该也能正常工作(在 Go tour 中)。

虽然我会说这不是很常见的设计。如果可能的话,我更喜欢互斥锁来锁定整个结构。一旦你进行了非常细粒度的锁定,你就必须非常小心,我会先探索其他选项。

  • 是的,你的结构中可以有多个互斥体
  • 不要使事情过于复杂:您可以使用单个互斥锁来保护对结构中两个元素之一的访问,即任何修改 mapint 的操作都可以共享同一个互斥
  • 当从其他函数引用您的结构时 - 使用像您的方法一样的指针 - 确保不复制该结构。复制的结构 - 带有互斥量 - 将导致 unpredictable/unsafe 结果

来自 golang mutex docs:

Values containing the types defined in this package (i.e. sync.Mutux) should not be copied.