【问题标题】:Mutex - global or local and idiomatic usage?Mutex - 全局或本地和惯用用法?
【发布时间】:2021-09-12 00:20:36
【问题描述】:

阅读 golang.org 和 stackoverflow 上的互斥锁示例后,我仍然不确定匿名函数的声明和惯用用法。所以我总结了几个例子。

示例 A、B 和 C 是否几乎相同,或者是否存在我没​​有注意到的主要差异? 我更喜欢全局示例“B”。我想如果我小心一点,这可能是最简单的解决方案。

或者有没有更好的方法来使用互斥锁?

This example on go playground

package main

import (
    "fmt"
    "sync"
)

type MuContainer struct {
    sync.RWMutex
    data int
}

var mucglobal = &MuContainer{}

func main() {

    // A: Global declaration - working: adds 45
    for i := 0; i < 10; i++ {
        go func(j int, mucf *MuContainer) {
            mucf.Lock()
            mucf.data += j
            mucf.Unlock()
        }(i, mucglobal)
    }

    // B: Global only - working: adds 45
    for i := 0; i < 10; i++ {
        go func(j int) {
            mucglobal.Lock()
            mucglobal.data += j
            mucglobal.Unlock()
        }(i)
    }

    // C: Local declaration - working: adds 45
    muclocal := &MuContainer{}
    for i := 0; i < 10; i++ {
        go func(j int, mucf *MuContainer) {
            mucf.Lock()
            mucf.data += j
            mucf.Unlock()
        }(i, muclocal)
    }

    // // D: Pointer to struct - not working: adds 0
    // // I guess because it points directly to the struct.
    // for i := 0; i < 10; i++ {
    //  go func(j int, mucf *MuContainer) {
    //      mucf.Lock()
    //      mucf.data += j
    //      mucf.Unlock()
    //  }(i, &MuContainer{})
    // }

    for {
        mucglobal.RLock()
        muclocal.RLock()
        fmt.Printf("global: %d / local: %d\n", mucglobal.data, muclocal.data)
        if mucglobal.data == 90 && muclocal.data == 45 {
            muclocal.RUnlock()
            mucglobal.RUnlock()
            break
        }
        muclocal.RUnlock()
        mucglobal.RUnlock()
    }
}

【问题讨论】:

  • 查看相关/可能的重复:When do you embed mutex in struct in Go?
  • A、B 和 C 之间没有实质性区别。您可能在这里高估了“惯用语”。
  • A 和 B 是相同的。 C 在现实世界的代码中可能会或可能不会以不同的方式工作(取决于是否有其他代码访问相同的包 var),但在此代码中,它与 A 和 B 相同。D 在这种情况下没有任何意义,可能或可能在任何其他假设情况下无效。
  • 你混淆了不同的东西。互斥锁是互斥锁。通常,您使用 *sync.Mutex,而不是互斥锁,因为不得复制互斥锁。嵌入互斥体是可以的,但如果您对互斥体、结构字面量和 popinters 感到不舒服:为什么不使用简单的(未嵌入的)字段。你可能想多了。
  • 免责声明:我不知道您的代码要做什么或要解决哪个问题。有时全局或局部变量都可以,然后有一个块var ( xyzMu = new(sync.Mutex); xyz XYZ) 就可以了。互斥锁和受该互斥锁保护的变量并排放置。有时最好将互斥锁作为一个字段。如果您使用一个字段,您可以拥有一个“普通”字段或“嵌入”一个互斥锁(您的代码嵌入它)。对于该语言的新手来说,经验嵌入是有问题的。如果你做到正确,那么如何做到这一点并不重要。

标签: go mutex


【解决方案1】:
推荐的答案 Go Language

D 不起作用,因为您正在为每次迭代创建一个新结构。最后,您将拥有 10 个独立的 MuContainer 实例。

前两个选项在语义上是相同的。这两者的底线是每个 goroutine 共享相同的对象实例,这恰好是一个全局变量。

第二个类似,唯一的区别是锁定和更新的对象恰好是本地变量。同样,goroutine 正在处理对象的同一个实例。

所以它们之间并没有真正的不同,而且这三个都有它们的用途。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    相关资源
    最近更新 更多