Suppose I have a set of goroutines
wg := sync.WaitGroup{}
wg.Add(5)
go somefunction("A", &wg) //1
go somefunction("B", &wg) //2
go somefunction("A", &wg) //3
go somefunction("A", &wg) //4
go somefunction("B", &wg) //5
wg.Wait()
What I require is that only one goroutine of a particular string ("A" or "B" here) run concurrently. At any time only one of somefunction("A", &wg) should run. For example, //1 and //2 starts running concurrently. After //2 is completed, //5 starts running. After //1 is completed, any one of //3 or //4 starts running.
I was thinking of developing a key based mutex to solve around this issue.
somefunction(key string){
Lock(key)
//piece of code
Unlock(key)
}
The piece of code will be locked for the particular key here.
CodePudding user response:
Let somefunction
take a mutex param, and pass the same mutex instance for the same key.
func somefunction(mux *sync.Mutex, wg *sync.WaitGroup) {
mux.Lock()
defer mux.Unlock()
...
}
wg := &sync.WaitGroup{}
wg.Add(5)
muxA := &sync.Mutex{}
muxB := &sync.Mutex{}
go somefunction(muxA, wg) //1
go somefunction(muxB, wg) //2
go somefunction(muxA, wg) //3
go somefunction(muxA, wg) //4
go somefunction(muxB, wg) //5
wg.Wait()
If you want to keep using key-base access, you can store the mutexes in a map:
muxmap := map[string]*sync.Mutex{
"A": &sync.Mutex{},
"B": &sync.Mutex{},
}
go somefunction(muxmap["A"], wg)
CodePudding user response:
Probably can implement a special lock like
type StringKeyLock struct {
locks map[string]*sync.Mutex
mapLock sync.Mutex // to make the map safe concurrently
}
func NewStringKeyLock() *StringKeyLock {
return &StringKeyLock{locks: make(map[string]*sync.Mutex)}
}
func (l *StringKeyLock) getLockBy(key string) *sync.Mutex {
l.mapLock.Lock()
defer l.mapLock.Unlock()
ret, found := l.locks[key]
if found {
return ret
}
ret = &sync.Mutex{}
l.locks[key] = ret
return ret
}
func (l *StringKeyLock) Lock(key string) {
l.getLockBy(key).Lock()
}
func (l *StringKeyLock) Unlock(key string) {
l.getLockBy(key).Unlock()
}
Then to initialize a "global" StringKeyLock
var stringKeyLock = NewStringKeyLock()
Last, to use it
func somefunction(key string){
stringKeyLock.Lock(key)
//piece of code
stringKeyLock.Unlock(key)
}