defer mutex.Unlock () в golang иногда никогда не вызывается - PullRequest
0 голосов
/ 10 июля 2020

Код переписан, чтобы не было путаницы, поэтому я надеюсь, что это имеет смысл (и что я не устранил проблему, переписав код). Проблема в том, что иногда defer Mutex.Unlock() никогда не происходит, делая списки заблокированными навсегда, как описано ниже

У меня есть список OuterStruct, где каждый элемент содержит список InnerInt. Оба этих списка могут изменяться одновременно в зависимости от происходящего. В нашем случае, если соединение websocket выходит из строя или появляется.

У меня есть функция, которая возвращает некоторые данные из каждого OuterStruct, включая значения int для всех InnerInt объектов для каждого OuterStruct. Итак, поскольку оба этих списка можно изменять одновременно, я использую Mutex для обоих из них. Итак, сначала я блокирую «внешний» список и выполняю defer outerStructList.Mutex.Unlock(). Затем я перебираю внешний список и для каждого элемента запускаю (outer *OuterStruct) getInnerInts(). Эта функция сделает Mutex.Lock() во внутреннем списке. Итерируйте этот список, получите все фактические значения int и верните массив этих int. Внешняя функция установит этот массив в одно из полей возвращаемого объекта плюс другое поле, а затем перейдет к следующему объекту.

Иногда случается, что Unlock () во внутреннем списке никогда бывает. Хотя я использую defer outer.InnerInts.Mutex.Unlock(). Единственное, что происходит после этого, - это то, что я повторяю элементы и добавляю значение int в массив целых чисел, затем массив возвращается, и в этот момент, как я предполагаю, должно произойти Unlock.

Я знаю из этого я, вероятно, мог бы немного улучшить этот код, но есть ли у кого-нибудь идеи, почему внутренний мьютекс иногда никогда не разблокируется? Что могло бы случиться между Lock() и функциональностью функции (итерация массива), чтобы функция никогда не возвращалась и, следовательно, Mutex никогда не разблокировался?

func getAllOuterStructs() []int {
    outerStructsList.Mutex.Lock()
    defer outerStructsList.Mutex.Unlock()
    var returnOuterStructsToSend []OuterStructToSend
    for _, rangedOuterStruct := range outerStructsList {
        outerStructToSend := OuterStructToSend{}
        outerStructToSend.OtherValue := rangedOuterStruct.OtherValue
        outerStructToSend.IntList := rangedOuterStruct.getInnerInts()
        returnOuterStructsToSend = append(returnOuterStructsToSend, outerStructToSend)
    }

    return returnOuterStructsToSend
}
func (outer *OuterStruct) getInnerInts() []int {
    outer.InnerInts.Mutex.Lock()
    defer outer.InnerInts.Mutex.Unlock()
    outerInts := outer.InnerInts
    var returnInts []int
    for _, rangedInt := range outerInts {
        returnInts = append(returnInts, rangedInt.IntVal)
    }

    return returnInts
}
...