Home > Software design >  Concurrency on keys in a sync map
Concurrency on keys in a sync map

Time:07-03

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