当前位置: > > > > 重现“致命错误:并发映射读取和映射写入”
重现“致命错误:并发映射读取和映射写入”
来源:stackoverflow
2024-05-01 11:00:35
0浏览
收藏
积累知识,胜过积蓄金银!毕竟在Golang开发的过程中,会遇到各种各样的问题,往往都是一些细节知识点还没有掌握好而导致的,因此基础知识点的积累是很重要的。下面本文《重现“致命错误:并发映射读取和映射写入”》,就带大家讲解一下知识点,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~
问题内容
我正在调试我的程序,以发现错误 致命错误:并发地图读取和地图写入 。程序可以简化为:
package main
import (
"sync"
"time"
)
func read(channelmap *map[int]chan bool, key int, mutex *sync.mutex) {
mutex.lock()
(*channelmap)[key] = make(chan bool, 1)
mutex.unlock()
defer func() {
mutex.lock()
delete((*channelmap), key)
mutex.unlock()
}()
select {
case <-(*channelmap)[key]:
{
}
case <-time.after(time.second):
{
}
}
}
func write(channelmap *map[int]chan bool, key int, mutex *sync.mutex) {
mutex.lock()
if channel, exist := (*channelmap)[key]; exist {
channel <- true
}
mutex.unlock()
}
func main() {
mutex := &sync.mutex{}
channelmap := make(map[int]chan bool)
for i := 0; i < 100; i++ {
go func() {
for {
read(&channelmap, 0, mutex)
time.sleep(time.millisecond)
}
}()
go func() {
for {
write(&channelmap, 0, mutex)
time.sleep(time.millisecond)
}
}()
}
time.sleep(10 * time.minute)
}
对于这个程序,只有 channelmap 和 mutex 在不同的函数中共享,其他所有内容都是参数化的。
有多个 read 和 write,他们有权访问 channelmap,即存储 channel 的地图。 read 在某个给定时间(示例代码中为 1 秒)等待来自某个通道的值,并且当该通道存在于 channelmap 中时,write 向该通道发送一个值。
对 channelmap 的每次访问都受到共享 sync.mutex 的保护,唯一的例外是
select {
case <-(*channelMap)[key]:
{
}
case <-time.After(time.Second):
{
}
}
我认为这是唯一的漏洞,但使用简化的程序我仍然无法重现该错误。有人可以向我解释一下这个程序中可能存在的逻辑缺陷吗?
正确答案
并发修改数据结构时,所有读取和写入都必须受到互斥锁的保护。
这部分:case <-(*channelMap)[key]: 无需持有锁即可访问 channelMap。
在两种情况下可以并发访问数据结构:
- 零个作者,一个或多个读者,或者
- 一位作者,零位读者。
以上就是《重现“致命错误:并发映射读取和映射写入”》的详细内容,更多关于的资料请关注米云公众号!
