2015-10-22 2 views
0

У меня есть куча функций в программе Go, работающей над структурой, которая использует мьютекс для управления параллельным доступом к своим функциям.Устранение дублирования блокировки мьютекса в Go

Некоторые из этих функций, которые работают с определенными данными, нуждаются в блокировках и тем самым используют mutex.Lock(), чтобы получить мьютекс, который управляет доступом к этим данным. Сегодня я столкнулся с проблемой, когда два из этих методов блокировки называют друг друга. Как только mutex.Lock() вызывается во второй раз, он блокирует - конечно.

Проблема я столкнулся очень похож на этот код: http://play.golang.org/p/rPARZsordI

Есть ли лучшие практики в Go о том, как решить эту проблему? Насколько я знаю, рекурсивные блокировки недоступны в Go.

+0

Есть один метод, который блокирует, записывает и отпирает, и пусть все другие методы используют, что один. – thwd

ответ

1

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

func (t *Thing) A() { t.Lock(); defer t.Unlock(); t.foo(); t.B() } 
func (t *Thing) B() { t.Lock(); defer t.Unlock(); t.bar() } 

то, что вы должны сделать вместо этого

func (t *Thing) A() { t.Lock(); defer t.Unlock(); t.foo(); t.b() } 
func (t *Thing) B() { t.Lock(); defer t.Unlock(); t.b() } 
func (t *Thing) b() { t.bar() } 
+0

Спасибо. Я просто реорганизовал код, чтобы закрепить ближе к фактическому доступу к данным, и это спасло проблему. Похоже, я был слишком глубоко в коде, чтобы увидеть эту очевидную ошибку. –

+0

Я бы предпочел, чтобы 'b()' сделал блокировку. Похоже, что из вашего примера 't.bar()' является ресурсом, который является одновременно чувствительным, а не 'A()' и 'B()' – atedja

+0

Так может быть 't.foo()'. Речь идет о композитоспособности, случаях, когда вам нужно делать 't.foo()' и 't.bar()' в одной транзакции. Нижеследующие методы не экспортируются, поэтому они не должны использоваться только вне пакета. –