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


评论