Trying to use a sync map in golang to provide ability to acquire a lock on a particular string(say "LOCK1").
package main
import (
"fmt"
"sync"
"time"
)
var lockMap sync.Map
func main(){
counter := func(key string,routineId string) {
_,ok := lockMap.Load(key)
if(ok){
fmt.Println(key " skipped by " routineId)
return}
lockMap.Store(key,true)
defer lockMap.Delete(key)
for i := 0; i < 10; i {
fmt.Println(key " locked by " routineId)
}
}
// Starting some goroutines
go counter("LOCK1","routine1")
go counter("LOCK1","routine2")
go counter("LOCK1","routine3")
go counter("LOCK1","routine4")
go counter("LOCK1","routine5")
//adding some sleep so the routines can execute for sometime
time.Sleep(time.Second)
}
I am aware that sync map uses a RWMutex under the hood. But, I am trying to understand if sync map allows multiple writes on different keys at the same time or only a single routine can do a write on the entire map at one time?
So let's say the key "LOCK1" is being set by routine1, would routine2 be able to set a new value "LOCK2" concurrently or does it have to wait for the first write to finish.
CodePudding user response:
For each key, you want to access the existing lock, or create a new lock if there isn't one. With sync.Map.LoadOrStore
you can do this atomically.
// Pre-allocate a new lock, in case it's needed for this key.
newLockIfNeeded = new(sync.Mutex)
lock, _ = lockMap.LoadOrStore(key, newLockIfNeeded)
// Safely acquired the (potentially new) lock for the key
lock.Lock()
defer lock.Unlock()
// do work ...
CodePudding user response:
I ended up using a sync map of key -> mutex. Thanks for the pointers Hymns for Disco. For reference here is the working impl:
package main
import (
"fmt"
"sync"
"time"
)
//var lockMap sync.Map
var lockMap2 sync.Map
func main(){
//lockMap2 := make(map[string]*sync.Mutex)
counter := func(key string,routineId string) {
mutex,_ := lockMap2.LoadOrStore(key,&sync.Mutex{})
mutex.(*sync.Mutex).Lock()
defer mutex.(*sync.Mutex).Unlock()
for i := 0; i < 100; i {
fmt.Println(key " locked by " routineId)
}
}
// Starting some goroutines
go counter("LOCK1","routine1")
go counter("LOCK1","routine2")
go counter("LOCK1","routine3")
go counter("LOCK1","routine4")
go counter("LOCK1","routine5")
//adding some sleep so the routines can execute for sometime
time.Sleep(time.Second)
}