英文:
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("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
}
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<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()
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论