douxin9135 2019-05-05 02:23
浏览 81

如何在没有bug的情况下通过按键编写互斥锁?

I want write a mutex with key just like https://github.com/im7mortal/kmutex ,but in different ideas.Just store the mutex in the hashmap.But there are always some deadlock in my code.How can I find the bug? Or are there better ways to write the key mutex?

package kmutex

import (
    "sync"
)

type keyMutex struct {
    localLockMap map[string]*sync.Mutex
    globalLock   sync.Mutex
}

func NewKeyMutex() *keyMutex {
    return &keyMutex{localLockMap: map[string]*sync.Mutex{}}
}

func (km *keyMutex) Lock(key string) {
    km.globalLock.Lock()

    wl, ok := km.localLockMap[key]

    if !ok {
        wl = &sync.Mutex{}
        km.localLockMap[key] = wl
    }

    km.globalLock.Unlock()

    wl.Lock()
}

func (km *keyMutex) Unlock(key string) {
    km.globalLock.Lock()

    wl, ok := km.localLockMap[key]

    if !ok {
        km.globalLock.Unlock()
        return
    }

    delete(km.localLockMap, key)

    km.globalLock.Unlock()

    wl.Unlock()
}

and test code is below

func TestKeyMutex1(t *testing.T) {

    keyMutex := kmutex.NewKeyMutex()

    //var keyMutex sync.Mutex

    var count = 0

    var wg sync.WaitGroup

    var num = 100

    for i := 1; i <= num; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            keyMutex.Lock("a")
            count += i
            keyMutex.Unlock("a")
        }(i)
    }

    wg.Wait()

    println(count)

}

There are always deadlock in it.After I remove the line delete(km.localLockMap, key).The deadlock is gone! But I still cannot understand it

  • 写回答

2条回答 默认 最新

  • dsbm49845 2019-05-05 04:02
    关注

    The problem is indeed deleting the mutex in the map.

    Considering just have three locks in the same entry ("a" in your case) running in the following order (in multiple goroutines, of course):

    keyMutex.Lock("a") // lock1
    keyMutex.Lock("a") // lock2
    keyMutex.Lock("a") // lock3
    keyMutex.Unlock("a") // unlock1
    keyMutex.Unlock("a") // unlock2
    keyMutex.Unlock("a") // unlock3
    

    lock1 creates a mutex in the map, and then lock2 and lock3 acquire the same mutex, blocking on the Lock of the mutex. unlock1 finds the mutex, unlocks it and removes it from the map, unblocking lock2 (or lock3, but for discussion's sake, let's say it is lock2). But when unlock2 or unlock3 runs, it finds no mutex in the map, unlocking nothing, and keeps lock3 blocking, thus a deadlock.

    The line removing mutex from the map simply don't make sense: a mutex is re-usable and in the context it is only sensible to have a same mutex for same entry.

    评论

报告相同问题?

悬赏问题

  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line