如何在Golang中设置基于密钥的互斥锁(Lock和Unlock)?

huangapple go评论72阅读模式
英文:

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

问题

假设我有一组goroutine:

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

我需要的是,只有一个特定字符串(这里是"A"或"B")的goroutine可以同时运行。在任何时候,只有一个somefunction("A", &wg)可以运行。例如,//1和//2开始同时运行。在//2完成后,//5开始运行。在//1完成后,//3或//4中的任何一个开始运行。

我考虑开发一个基于键的互斥锁来解决这个问题。

somefunction(key string){
   Lock(key)
   //一段代码
   Unlock(key)
}

这段代码将会为特定的键进行锁定。

英文:

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.

答案1

得分: 1

somefunction接受一个互斥锁参数,并为相同的键传递相同的互斥锁实例。

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

如果你想继续使用基于键的访问,可以将互斥锁存储在一个映射中:

muxmap := map[string]*sync.Mutex{
    "A": &sync.Mutex{},
    "B": &sync.Mutex{},
}

go somefunction(muxmap["A"], wg)
英文:

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)

答案2

得分: 1

可能可以实现一个特殊的锁,类似于:

type StringKeyLock struct {
    locks map[string]*sync.Mutex

    mapLock sync.Mutex // 用于在并发情况下保证 map 的安全性
}

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

然后初始化一个"全局"的 StringKeyLock:

var stringKeyLock = NewStringKeyLock()

最后,使用它:

func somefunction(key string){
   stringKeyLock.Lock(key)
   // 一段代码
   stringKeyLock.Unlock(key)
}
英文:

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

huangapple
  • 本文由 发表于 2021年9月30日 22:03:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/69393601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定