今天早上一来领导告诉我消息源出问题了,赶紧检查日志,没有报错,于是跟着看nohup输出,看到一个error导致了程序崩溃,fatal error: concurrent map iteration and map write.

看到这个错误信息,很容易就想到了,可能是在多线程中,同时对map进行了遍历和写操作,导致的崩溃。然后通过对代码进行检查,发现了确实有一处地方,没有对遍历map的操作加锁,导致了这个问题。之前只考虑到了读和写会引发崩溃,直到今天发生崩溃了才发现这个问题。

上一下之前的模拟代码:

func MapMuxTest() {
    mMap := make(map[int]string)
    var mux sync.RWMutex
    mMap[1] = "new rap"
    mMap[2] = "new star"
    mMap[3] = "mo"
    mMap[4] = "dong"
    mMap[5] = "shan"
    mMap[6] = "ba"

    go func(mux *sync.RWMutex, mMap map[int]string) {
        ti := time.NewTimer(time.Nanosecond * 2)
        idx := 1
        for {
            <- ti.C

            mux.Lock()
            mMap[idx] = "mdsb"        // map write
            idx++
            if idx >= 7 {
                idx = 1
            }
            mux.Unlock()

            ti.Reset(time.Nanosecond * 2)
        }
    }(&mux, mMap)

    ti := time.NewTimer(time.Millisecond)
    for {
        <- ti.C

        // 这里没有对遍历操作加锁,导致和上面的写操作冲突
        for k, _ := range mMap {    // map iteration
            mux.RLock()
            str := mMap[k]
            fmt.Println(str)
            mux.RUnlock()
        }

        ti.Reset(time.Millisecond)
    }
}

之后,把代码修改了一下,就是把加锁解锁的操作放在了遍历的外面,避免了遍历map和写map的冲突。

mux.RLock()
for k, _ := range mMap {
    str := mMap[k]
    fmt.Println(str)
}
mux.RUnlock()

本篇到此结束,简单记录一下这个问题。