Home > Mobile >  How to setup key based Mutex (Lock and Unlock) in Golang?
How to setup key based Mutex (Lock and Unlock) in Golang?

Time:10-01

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)
}

  • Related