带互斥锁的竞争条件以及在何处嵌入锁,父结构或子结构?

时间:2019-06-18 09:55:58

标签: go struct concurrency mutex race-condition

  1. 我看到有人在单个结构中排除了一些互斥。有必要吗?还是我们可以简单地在这里放一把锁? 例如:
type Session struct {
    // some other irrelevant code
    pingLock sync.Mutex
    // some other irrelevant code
    streamLock sync.Mutex
    // some other irrelevant code
    shutdownLock sync.Mutex
}
  1. 如果一个结构包含另一个结构,而子结构包含一个映射或切片,我应该在哪里放置互斥体,父结构或子结构?
  2. 为什么Mutex.Lock()在我的代码中不起作用?每次我进行种族测试时,都会显示有种族。

起初,我试图解决前两个问题,所以我编写了一些演示代码对其进行测试。我尝试在子struct中使用锁,然后在父st​​ruct中锁定状态,但是它们都不起作用。比赛测试一直说存在比赛条件。 我已经尝试过t.Lock()t.data.Lock()

type Test struct {
    name string
    data Data
    sync.RWMutex //Should I put it here?
}

type Data struct {
    d map[string]int
    sync.RWMutex // Should I put it here?
}

func (t *Test) add(key string) {
    t.data.Lock()
    defer t.data.Unlock()
    t.data.d[key] += 1
}

func (t *Test) read() {
    for {
        t.data.Lock()
        _= t.data.d["test"]
        t.data.Unlock()
    }
}

func main() {

    t := &Test{}
    t.name = "oops"
    t.data = Data{}
    t.data.d = make(map[string]int)
    t.data.d["test"] = 1

    for i := 0; i <= 10; i++ {
        go func(t *Test) {
            t.add("test")
        }(t)
        go func(t *Test) {
            t.read()
        }(t)
    }
    time.Sleep(time.Second * 3)
    fmt.Printf("result is %v", t.data.d["test"])

2 个答案:

答案 0 :(得分:0)

  

比赛测试一直说存在比赛条件。


声明

fmt.Printf("result is %v", t.data.d["test"])

传递参数

t.data.d["test"]

按值。它是按分配复制的,这是读取的。

您需要通过互斥量保护读取。

t.data.Lock()
fmt.Printf("result is %v\n", t.data.d["test"])
t.data.Unlock()

答案 1 :(得分:0)

正如@peterSO所述,该错误是由“ fmt.Printf(“结果为%v \ n”,t.data.d [“ test”]))引起的。 经过数小时的挖掘,我似乎找到了有关前两个问题的答案。我误解了互斥的概念。互斥锁用于保护资源,而不是锁定自身的内存(在我的示例中为结构本身)。 对于第一个问题: 如果一个goroutine执行

之类的代码
s.pingLock.Lock()
\\ some logic 1
s.pingLock.Unlock()
streamLock
\\ some logic 2
streamUnlock

因此,当一个goroutine执行此代码并获取s.streamLock.Lock()时,直到它被解锁,其他go例程才能执行some logic 2,但是任何goroutine如果得到{{ 1}}。如果仅使用一个锁,则如果一个go例程获得了锁,则其他人都无法获得该锁,则所有其他执行都将被阻塞。

对于第二个问题: 如果理解以上解释。然后第二个问题也被回答。将互斥锁放在您想要的任何位置,因为它只是保护资源的锁,也就是说,是代码本身。不过,我敢肯定有一种很好的惯用方式。

我不确定采用这种方式是否正确。如果有人有其他意见或更好的答案,请告诉我。