Golang的互斥锁有时候会起作用吗?

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

golang mutex sometimes works?

问题

我有一个goroutine,有时会生成可怕的“fatal error: concurrent map read and map write”错误。回溯指示错误出现在s := db.FileInfo...的地方。

func HMAC(source string, i int) {
    var value [4]byte
    var mutex sync.Mutex
    defer WG.Done()
    hash, err := HashString(source);
    if err != nil {
        log.Critical("HashString error: ",err)
    }
    log.Trace("Slice:",i,"Authentication hash =",hash)
    rand.Seed(time.Now().UnixNano())
    mutex.Lock()    // 保护Map的活动
    defer mutex.Unlock()
    s := db.FileInfo.Slices[SliceName]
    s.Block[i].HMAC = hash
    for j:=0; j<32; j++ {
        off := rand.Intn(DataLen-5)  // 4应该足够,但要保险起见
        s.Block[i].Random[j].Offset = off
        for k:=0; k<4; k++ {
            value[k] = source[off+k]
        }
        s.Block[i].Random[j].Value = value
    }
    db.FileInfo.Slices[SliceName] = s
}

HashString(source)函数计算密集型,因此适合作为goroutine。互斥锁调用后的代码在计算上都相对简单,所花费的时间不到HashString(source)调用的1%。go vet对该例程及其调用者都没有问题。

该函数被调用了32次,如下所示:

util.WG.Add(32)
for i:=0; i<32; i++ {
    off := i*util.BlockLen
    go util.HMAC(string(tblock[off:off+util.BlockLen-1]),i)
}
util.WG.Wait()

我发现这个错误大约在每六次程序调用中出现一次,非常不一致。

有人发现我做错了什么吗?这个问题的不确定性让我困惑。哦,顺便说一下,它在一个12线程的I7上运行。另外:go版本go1.7.5 linux/amd64。

英文:

I have the following goroutine that SOMETIMES generates the dreaded "fatal error: concurrent map read and map write". Traceback indicates its on the s := db.FileInfo... map reference.

func HMAC(source string, i int) {
    var value [4]byte
    var mutex sync.Mutex
    defer WG.Done()
    hash, err := HashString(source);
    if err != nil {
            log.Critical(&quot;HashString error: &quot;,err)
    }
    log.Trace(&quot;Slice:&quot;,i,&quot;Authentication hash =&quot;,hash)
    rand.Seed(time.Now().UnixNano())
    mutex.Lock()    // Protect Map activity
    defer mutex.Unlock()
    s := db.FileInfo.Slices[SliceName]
    s.Block[i].HMAC = hash
    for j:=0; j&lt;32; j++ {
            off := rand.Intn(DataLen-5)  // 4 should do, but be safe
            s.Block[i].Random[j].Offset = off
            for k:=0; k&lt;4; k++ {
                    value[k] = source[off+k]
            }
            s.Block[i].Random[j].Value = value
    }
    db.FileInfo.Slices[SliceName] = s
}

The HashString(source) function is computationally intensive, so is appropriate as a goroutine. The code after the mutex calls is all relatively trivial computationally, taking less than 1% of the time the HashString(source) call takes. go vet is clean on the routine and its caller.

This function is called (32) times as follows:

    util.WG.Add(32)
    for i:=0; i&lt;32; i++ {
            off := i*util.BlockLen
            go util.HMAC(string(tblock[off:off+util.BlockLen-1]),i)
    }
    util.WG.Wait()

I get the error about once out of every half-dozen or so invocations of the program, very inconsistantly.

Anybody spot what I've done wrong? The SOMETIMES nature of this problem is perplexing me. Oh, FWIW, its running on a 12 thread I7. Also: go version go1.7.5 linux/amd64.

答案1

得分: 8

每次执行该函数都会创建一个新的互斥锁,因此实际上并没有保护任何内容。你需要通过在其他地方创建它(例如作为全局变量)来确保函数始终使用同一个互斥锁。

英文:

Every execution of the function is going to create a new mutex, so it isn't actually protecting anything. You need to have the function always use the same mutex by creating it elsewhere (e.g., as a global variable).

答案2

得分: 0

将函数中的mutex变量改为非局部变量。以下是修复后的代码:

var mutex sync.Mutex

func HMAC(source string, i int) {
    var value [4]byte
    // var mutex sync.Mutex
    defer WG.Done()
    ...

请注意,我只提供翻译服务,不会执行代码。如果您有其他问题,请告诉我。

英文:

Make mutex variable not local in your function. This is fixed code:

var mutex sync.Mutex

func HMAC(source string, i int) {
    var value [4]byte
    // var mutex sync.Mutex
    defer WG.Done()
    ... 

huangapple
  • 本文由 发表于 2017年3月21日 11:55:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/42918161.html
匿名

发表评论

匿名网友

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

确定