var mutexes map[string]*sync.Mutex
var m *sync.Mutex
if mForID, ok := mutexes[ID]; ok {
m = mForID
} else {
m = &sync.Mutex{}
mutexes[ID] = m
}
m.Lock()
defer m.Unlock()
{
// Code here I want to protect from concurrent access, if the ID is the same.
// Read some data
// Mutate it
// Write the data back
}
What I am trying to do is prevent data races between go routines that are using the same ID. If the ID is different, there is no problem, but if a go routine is using the same ID as another one, then it must wait to access, modify, and write the data, until the other go routine is finished.
I’ve tested this code and it seems to work as I want it to. If I comment out the defer m.Unlock() line then make two request with the same ID, the second request is permanently locked. Then if I make a third request with a different ID it is allowed to proceed, which is the functionality I am looking for.
Are there any gotchas with the code I have written or a better way to have mutexes that are unique to a specific ID?
I also probably need a way to delete the mutex from the map after a certain period of time.
You need a mutex to protect your mutexes map because mutating a map is not “goroutine safe.” What is it you’re trying to do, though? A threadsafe map of mutexes looks like something that might be solvable instead with channels.
Yes after reading Sean and your replies I believe a channel is the way to go.
I’m going to do some thinking and try to get a solution with channels working. I seem to have a hard time determining when to use channels vs mutexes.
Thanks again for pointing me in the right direction
Ah I see. So each go routine, regardless of the ID, would have to “wait in line” to access the map.
This is what I’m trying to do:
My server is receiving simultaneous http requests. My server has to do 3 things after it receives one of these requests.
Retrieve a file from bucket storage using the ID contained in the body of the request.
Merge data contained in the body of the request into this file.