Go map and concurrency security issues

在同一时间段内,让不同 goroutine 中的代码,对同一个map进行读写操作是不安全的。map值本身可能会因这些操作而产生混乱,相关的程序也可能会因此发生不可预知的问题。

我们可以用如下代码展示 map 的并发安全问题。

package main

func main() {
	m := make(map[int]int)

	go func() {
		for {
			_ = m[1]
		}
	}()

	go func() {
		for {
			m[2] = 2
		}
	}()

	select {}
}

错误信息是: fatal error: concurrent map read and map write。

如果你查看 Go 的源代码: hashmap_fast.go#L118,会看到读的时候会检查 hashWriting 标志, 如果有这个标志,就会报并发错误。

写的时候会设置这个标志: hashmap.go#L542

h.flags |= hashWriting

hashmap.go#L628 设置完之后会取消这个标记。

当然,代码中还有好几处并发读写的检查, 比如写的时候也会检查是不是有并发的写,删除键的时候类似写,遍历的时候并发读写问题等。

有时候,map 的并发问题不是那么容易被发现, 你可以利用-race参数来检查。

那么我们如何保证 map 的并发安全呢?

点击阅读更多看全文。

Related