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

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

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

问题

假设我有一组goroutine:

  1. wg := sync.WaitGroup{}
  2. wg.Add(5)
  3. go somefunction("A", &wg) //1
  4. go somefunction("B", &wg) //2
  5. go somefunction("A", &wg) //3
  6. go somefunction("A", &wg) //4
  7. go somefunction("B", &wg) //5
  8. wg.Wait()

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

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

  1. somefunction(key string){
  2. Lock(key)
  3. //一段代码
  4. Unlock(key)
  5. }

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

英文:

Suppose I have a set of goroutines

  1. wg := sync.WaitGroup{}
  2. wg.Add(5)
  3. go somefunction("A", &wg) //1
  4. go somefunction("B", &wg) //2
  5. go somefunction("A", &wg) //3
  6. go somefunction("A", &wg) //4
  7. go somefunction("B", &wg) //5
  8. 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.

  1. somefunction(key string){
  2. Lock(key)
  3. //piece of code
  4. Unlock(key)
  5. }

The piece of code will be locked for the particular key here.

答案1

得分: 1

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

  1. func somefunction(mux *sync.Mutex, wg *sync.WaitGroup) {
  2. mux.Lock()
  3. defer mux.Unlock()
  4. ...
  5. }
  1. wg := &sync.WaitGroup{}
  2. wg.Add(5)
  3. muxA := &sync.Mutex{}
  4. muxB := &sync.Mutex{}
  5. go somefunction(muxA, wg) //1
  6. go somefunction(muxB, wg) //2
  7. go somefunction(muxA, wg) //3
  8. go somefunction(muxA, wg) //4
  9. go somefunction(muxB, wg) //5
  10. wg.Wait()

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

  1. muxmap := map[string]*sync.Mutex{
  2. "A": &sync.Mutex{},
  3. "B": &sync.Mutex{},
  4. }
  5. go somefunction(muxmap["A"], wg)
英文:

Let somefunction take a mutex param, and pass the same mutex instance for the same key.

  1. func somefunction(mux *sync.Mutex, wg *sync.WaitGroup) {
  2. mux.Lock()
  3. defer mux.Unlock()
  4. ...
  5. }
  1. wg := &sync.WaitGroup{}
  2. wg.Add(5)
  3. muxA := &sync.Mutex{}
  4. muxB := &sync.Mutex{}
  5. go somefunction(muxA, wg) //1
  6. go somefunction(muxB, wg) //2
  7. go somefunction(muxA, wg) //3
  8. go somefunction(muxA, wg) //4
  9. go somefunction(muxB, wg) //5
  10. wg.Wait()

If you want to keep using key-base access, you can store the mutexes in a map:

  1. muxmap := map[string]*sync.Mutex{
  2. "A": &sync.Mutex{},
  3. "B": &sync.Mutex{},
  4. }
  5. go somefunction(muxmap["A"], wg)

答案2

得分: 1

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

  1. type StringKeyLock struct {
  2. locks map[string]*sync.Mutex
  3. mapLock sync.Mutex // 用于在并发情况下保证 map 的安全性
  4. }
  5. func NewStringKeyLock() *StringKeyLock {
  6. return &StringKeyLock{locks: make(map[string]*sync.Mutex)}
  7. }
  8. func (l *StringKeyLock) getLockBy(key string) *sync.Mutex {
  9. l.mapLock.Lock()
  10. defer l.mapLock.Unlock()
  11. ret, found := l.locks[key]
  12. if found {
  13. return ret
  14. }
  15. ret = &sync.Mutex{}
  16. l.locks[key] = ret
  17. return ret
  18. }
  19. func (l *StringKeyLock) Lock(key string) {
  20. l.getLockBy(key).Lock()
  21. }
  22. func (l *StringKeyLock) Unlock(key string) {
  23. l.getLockBy(key).Unlock()
  24. }

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

  1. var stringKeyLock = NewStringKeyLock()

最后,使用它:

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

Probably can implement a special lock like

  1. type StringKeyLock struct {
  2. locks map[string]*sync.Mutex
  3. mapLock sync.Mutex // to make the map safe concurrently
  4. }
  5. func NewStringKeyLock() *StringKeyLock {
  6. return &StringKeyLock{locks: make(map[string]*sync.Mutex)}
  7. }
  8. func (l *StringKeyLock) getLockBy(key string) *sync.Mutex {
  9. l.mapLock.Lock()
  10. defer l.mapLock.Unlock()
  11. ret, found := l.locks[key]
  12. if found {
  13. return ret
  14. }
  15. ret = &sync.Mutex{}
  16. l.locks[key] = ret
  17. return ret
  18. }
  19. func (l *StringKeyLock) Lock(key string) {
  20. l.getLockBy(key).Lock()
  21. }
  22. func (l *StringKeyLock) Unlock(key string) {
  23. l.getLockBy(key).Unlock()
  24. }

Then to initialize a "global" StringKeyLock

  1. var stringKeyLock = NewStringKeyLock()

Last, to use it

  1. func somefunction(key string){
  2. stringKeyLock.Lock(key)
  3. //piece of code
  4. stringKeyLock.Unlock(key)
  5. }

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:

确定