英文:
reproduce "fatal error: concurrent map read and map write"
问题
我正在调试一个程序,出现了一个名为fatal error: concurrent map read and map write
的错误。这个程序可以简化为以下代码:
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
函数,它们都可以访问存储channel
的channelMap
。read
函数会等待从特定的通道接收一个值,等待的时间为给定的时间(在示例代码中为1秒),而write
函数会在通道存在于channelMap
中时向该通道发送一个值。
对channelMap
的每次访问都受到共享的sync.Mutex
的保护,唯一的例外是:
select {
case <-(*channelMap)[key]:
{
}
case <-time.After(time.Second):
{
}
}
我认为这是唯一的漏洞,但是即使使用简化的程序,我仍然无法重现这个错误。有人能解释一下这个程序可能存在的逻辑缺陷吗?
英文:
I'm debugging my program for a bug fatal error: concurrent map read and map write
. The program can be simplified as:
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)
}
For this program, only channelMap
and mutex
are shared in different functions, everything else is parameterized.
There are multiple read
and write
, who have access to channelMap
, a map storing channel
. read
waits for a value from a certain channel for some given time (1 second in the example code), and write
send a value into the same channel when this channel exist in the channelMap
.
Every access to channelMap
has been protected by a shared sync.Mutex
and the only exception is
select {
case <-(*channelMap)[key]:
{
}
case <-time.After(time.Second):
{
}
}
I think this is the only vulnerability but with the simplified program I still couldn't reproduce the bug. Can someone explain to me the possible logical flaw in this program?
答案1
得分: 1
当同时修改数据结构时,所有的读写操作都必须由互斥锁保护。
这部分代码:case <-(*channelMap)[key]:
在没有持有锁的情况下访问了channelMap
。
对数据结构的并发访问可能存在两种情况:
- 零个写者,一个或多个读者;
- 一个写者,零个读者。
英文:
When modifying a data structure concurrently, all reads and writes must be protected by a mutex.
This part: case <-(*channelMap)[key]:
accesses channelMap
without holding a lock.
Concurrent access to a data structure is possible in two situations:
- Zero writers, one or more readers, or
- One writer, zero readers.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论