I have a struct, MyStruct, which contains a map. I want to make the access to the map safe for concurrent read and write but I also want to stick to the base Map and not use sync.Map.
For this reason I create on MyStruct methods for insert, delete and fetch which are protected by a mutex. The code looks like this
type MyStruct struct {
mu sync.Mutex
myMap map[string]string
}
func (myStruct *MyStruct) Add(val string) {
myStruct.mu.Lock()
myStruct.myMap[val] = val
myStruct.mu.Unlock()
}
func (myStruct *MyStruct) Remove(val string) {
myStruct.mu.Lock()
delete(myStruct.myMap, val)
myStruct.mu.Unlock()
}
func (myStruct *MyStruct) Fetch(val string) string {
myStruct.mu.Lock()
ret := delete(myStruct.myMap, val)
myStruct.mu.Unlock()
return ret
}
So far so good.
Some clients of MyStruct though need also to loop through myStruct.myMap and here comes my question. Which is the best design to make concurrent safe also loop operations performed not in methods of MyStruct? Currently I see 2 options
- Make the map
myMapand the mutexmuofMyStructpublic and move to the clients the responsibility to make the loop thread safe. This is simple but, somehow, feels likeMyStructdoes not care too much about its clients - Keep everything private and add a method that returns a copy of the map to clients which wants safely play with it. This seems better from an "encapsulation' point of view but, at the same time, sounds a bit heavy
Is there any other possibility? Any suggestion on which design is better?
Add,RemoveandRangeetc on the Map. Other routines can communicate to this routine through channels. Thus there is no locking involved anywhere. With go this can be implemeneted easily too. You can even pass the call back function too (through interface). In my opinion this is the most idiomatic way of achieving above result. - Sai Ravi Teja K