type Session struct {
// some other irrelevant code
pingLock sync.Mutex
// some other irrelevant code
streamLock sync.Mutex
// some other irrelevant code
shutdownLock sync.Mutex
}
起初,我试图解决前两个问题,所以我编写了一些演示代码对其进行测试。我尝试在子struct中使用锁,然后在父struct中锁定状态,但是它们都不起作用。比赛测试一直说存在比赛条件。
我已经尝试过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"])
答案 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例程获得了锁,则其他人都无法获得该锁,则所有其他执行都将被阻塞。
对于第二个问题: 如果理解以上解释。然后第二个问题也被回答。将互斥锁放在您想要的任何位置,因为它只是保护资源的锁,也就是说,是代码本身。不过,我敢肯定有一种很好的惯用方式。
我不确定采用这种方式是否正确。如果有人有其他意见或更好的答案,请告诉我。