我的目标是创建一个简单的 websocket 服务器。我使用 chan 来分发消息,例如通过调用<-messageChan
. 有messageChan
许多作家和读者。
但是,这个StackOverflow 问题让我害怕导致无意中的死锁。
我做了什么:
创建一个基本上做的测试:
chan int
用 0 到 1000填充 a 。
创建 100 个 goroutine 来调用<-chan
并将其添加到map[int]bool
.
t.Fatal
如果不是 1000,则调用。len(map[int]bool)
换句话说,竞争条件。
然而,测试并没有失败。恐怕,我做错了什么,chan
可能会陷入僵局。
代码
main_test.go
package main
import (
"log"
"sync"
"testing"
)
type MapMux struct {
sync.RWMutex
m map[int]bool
sync.WaitGroup
}
func (mux *MapMux) AddInt(i int) {
mux.RLock()
if _, isExist := mux.m[i]; isExist {
log.Fatal("race condition")
}
mux.RUnlock()
mux.Lock()
mux.m[i] = true
mux.Unlock()
mux.Done()
}
func TestChanRaceCondition(t *testing.T) {
l := 1000
c := make(chan int, l)
defer close(c)
for i := 0; i < l; i++ {
c <- i
}
mux := MapMux{sync.RWMutex{}, map[int]bool{}, sync.WaitGroup{}}
mux.Add(l)
for i := 0; i < 100; i++ {
go func(key int) {
for {
payload := <-c
log.Printf("go%d: %d", key, payload)
mux.AddInt(payload)
}
}(i)
}
mux.Wait()
if len(mux.m) != l {
t.Fatal("expected len:", l, ", actual len:", len(mux.m))
}
}
编辑:
该代码在该map[int]bool
字段中查找重复项。编辑:这是因为defer close(c)
。我应该检查通道是否为每个操作打开。
无论如何,这就是我学到的。希望这对新的 Golangers 有所帮助。
学习到教训了:
一个频道有很多作者和很多读者是可以的。
总是检查val, isOpen := <-chan
。如果isOpen
== false
,则停止使用该频道。
sync.RWMutex.RLock()
不保证其他 goroutine 对地图进行更改。所以,当心。这是应该做的。
func (mux *MapMux) AddInt(i int) {
mux.RLock()
if _, isExist := mux.m[i]; isExist {
log.Fatal("race condition")
}
mux.RUnlock()
mux.Lock()
if _, isExist := mux.m[i]; isExist {
log.Fatal("race condition")
}
mux.m[i] = true
mux.Unlock()
mux.Done()
}
MMMHUHU