2016-11-25 4 views
0

Интересная проблема возникла сегодня, когда у меня есть код, который содержит более одного Mutex, каждый из которых блокирует блокировку для разных карт.гонка данных, сообщенная с двух различных взаимных обморожений

Вот похожи на структуры моего исходного кода, который я использую:

type MyStruct struct { 
    dogMutex sync.RWMutex 
    dogMap map[int]Dog // keyed by PID 
    catMutex sync.RWMutex 
    catMap map[int]Cat // keyed by (localAddress + localPort) 
} 

Более подробный пример вопроса здесь: https://play.golang.org/p/eic8q2VrNq

После создания исполняемого файла с ' go build -race ... "сгенерированный исполняемый файл сообщает о следующей гонке

Поскольку код более сложный, чем приведенный выше пример, что гонка данных сообщается в областях, указанных в коде.

Следующий стек из реального приложения.

1) записи операции сообщили о wwww.go: 95 эквивалентно мой WRITE комментарий в коде (метадона)

2) предыдущий прочитать operattion сообщил о wwww.go: 218 эквивалентный моя READ комментарий в коде (MethodTwo)

================= 
WARNING: DATA RACE 
Write at 0x00c420017890 by goroutine 97: 
    runtime.mapassign1() 
     /usr/local/go/src/runtime/hashmap.go:442 +0x0 
    main.(*NetworkManager).MethodOne() 
     /opt/doppler/src/xxx/yyy/wwww.go:95 +0x745 

Previous read at 0x00c420017890 by goroutine 70: 
    runtime.mapiterinit() 
     /usr/local/go/src/runtime/hashmap.go:620 +0x0 
    main.NetworkManager.MethodTwo() 
     /opt/xxx/src/xxx/yyy/wwww.go:218 +0x1e9 
    main.(*NetworkManager).SomethingELse() 
     /opt/xxx/src/xxx/yyy/wwww.go:174 +0x99d 
    main.(*NetworkManager).SomethingFurther() 
     /opt/xxx/src/xxx/yyy/wwww.go:102 +0x3c 

мне интересно, если это правильный способ использования семафоров. Мой код имеет много параллелизма, но я фокусирую этот вопрос на том факте, что детектор гонки сообщает на основе Apples vs Bananas (два совершенно разных мьютекса)

+0

использование go версия go1.7 linux/amd64 – gextra

+2

У меня такое чувство, что вы удалили гонку в упрощенном примере. Можете ли вы сделать что-то, что реплицирует гонку, или предоставить фактические методы и типы из вашего кода? – JimB

+0

Код довольно взаимозависим. Это не помогло бы. Но, честно говоря, на самом деле нет никакой расы, за исключением того, что она сообщается. Вот почему я озадачен. – gextra

ответ

1

Просто собираюсь угадать, но одна общая причина этой проблемы случайно передает структуру, содержащую указатели по значению, а не ссылку. Например:

type MyStruct struct { 
    dogMutex sync.RWMutex 
    dogMap map[int]Dog // keyed by PID 
    catMutex sync.RWMutex 
    catMap map[int]Cat // keyed by (localAddress + localPort) 
} 

func (s MyStruct) Example() { 
    // this lock doesn't actually work, but the map access does because its a 
    // reference type 
    s.catMutex.Lock() 
    s.catMap[1] = Cat{} 
    s.catMutex.Unlock() 
} 

Другая возможность заключается в том, что, возможно, вы передаете карты в ваш INIT:

func (s *MyStruct) Init(cats map[int]Cat) { 
    s.catMap = cats 
} 

А потом вы изменяете карту где-то за пределами структуры. Если это так, вам нужно создать новую карту и скопировать все значения.

Кстати, go vet может обнаружить многие из этих проблем, попробуйте запустить его на вашем коде: https://golang.org/cmd/vet/. (Также стоит попробовать metalinter)

+0

, что моя проблема была (методы были по значению vs reference). Отличные предложения.Я не знал о ветеринарном инструменте или металлистере – gextra

Смежные вопросы