I'm getting a data race and I can't quite figure out why. Running my tests with the -race
command I've narrowed it down to trying to access a list.List
while reading from it, but my Mutexes don't seem to do anything.
I have a number of *list.Lists inside of an array like so:
type MyList struct {
mutex sync.Mutex
*list.List
}
type SomeObj struct {
data string
}
var myListOfLists [10]MyList
I'm reading and writing from the list like so:
list := myListOfLists[someIndex]
list.mutex.Lock()
for e := list.Front(); e != nil; e = e.Next() {
if (...) {
list.MoveToFront(e)
}
}
list.mutex.Unlock()
and in another goroutine also trying to read and build a full list to return
var fullCopy []*SomeObj
list := myListOfLists[someIndex]
list.mutex.Lock()
for e := list.Front(); e != nil; e = e.Next() {
fullCopy = append(fullCopy, e.Value.(SomeObj))
}
list.mutex.Unlock()
The statement list := myListOfLists[someIndex]
copies the array element to variable list
. This copies the mutex, thus preventing the mutex from working. The go vet
command reports this problem.
You can avoid the copy by using a pointer to the array element:
list := &myListOfLists[someIndex]
Another approach is to use an array of pointers to MyList
. While you are at it, you might as well use a list value instead a list pointer in MyList
:
type MyList struct {
mutex sync.Mutex
list.List
}
var myListOfLists [10]*MyList
for i := range myListOfLists {
myListOfLists[i] = &MyList{}
}