В Round()
вы блокируете мьютекс getHeightMu
и звоните getHeightManager()
. В котором вы снова пытаетесь заблокировать тот же мьютекс.
Мьютекс Go не является reentrant , что означает, что он не может быть снова заблокирован той же самой программой, если он уже заблокирован. Подробнее см. Рекурсивная блокировка в Go .
Попытка заблокировать уже заблокированный мьютекс является блокирующей операцией. Он будет блокироваться до тех пор, пока мьютекс будет разблокирован, а ваша подпрограмма станет счастливчиком, который снова сможет ее заблокировать (если другие подпрограммы также ожидают ее). Но разблокировка наступит только тогда, когда вернется Round()
, для завершения которого требуется getHeightManager()
, что никогда не произойдет. Это тупик.
Вам нужно заблокировать мьютекс только в одном месте, рядом с которым вы получаете к нему доступ. Поэтому используйте блокировку только внутри getHeightManager()
и удалите блокировку из Round()
(она все равно не получает доступ к защищенному ресурсу).
Также в зависимости от того, как часто новые менеджеры высоты создаются и добавляются на карту, может быть выгодно использовать sync.RWMutex
. Сначала вы можете заблокировать его только для чтения, а если менеджер высоты уже существует, вы можете вернуть его. Хорошей стороной этого является то, что несколько читателей могут получить к нему доступ одновременно, не блокируя друг друга. Только если вы обнаружите, что менеджер высоты еще не существует, вам придется установить блокировку записи.