golang mutex 有时有效?

golang mutex sometimes works?

我有以下 goroutine,有时会生成可怕的 "fatal error: concurrent map read and map write"。 Traceback 表明它在 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("HashString error: ",err)
    }
    log.Trace("Slice:",i,"Authentication hash =",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<32; j++ {
            off := rand.Intn(DataLen-5)  // 4 should do, but be safe
            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()

大约每六次调用该程序我就会遇到一次错误,非常不一致。

有人发现我做错了什么吗?有时这个问题的性质让我感到困惑。哦,FWIW,它的 运行 在 12 线程 I7 上。另外:go version go1.7.5 linux/amd64.

函数的每次执行都会创建一个新的互斥体,因此它实际上并没有保护任何东西。您需要通过在别处创建它(例如,作为全局变量)来让该函数始终使用相同的互斥量。

使 mutex 变量不在您的函数中。这是固定码:

var mutex sync.Mutex

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