我有以下goroutine,SOMETIMES生成可怕的“致命错误:并发映射读取和映射写入”。 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(源)调用所花费的时间不到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 go go7.7.5 linux / amd64。
答案 0 :(得分:6)
每次执行该函数都会创建一个新的互斥锁,因此它实际上并没有保护任何东西。您需要让函数始终在其他地方使用相同的互斥锁(例如,作为全局变量)。
答案 1 :(得分:0)
使互斥变量在您的函数中不是本地的。这是固定代码:
var mutex sync.Mutex
func HMAC(source string, i int) {
var value [4]byte
// var mutex sync.Mutex
defer WG.Done()
...