我有一台服务器,可以像这样处理连接Session
type Session struct {
conn *net.TCPConn //the tcp connection from client
recvChan chan []byte
closeNotiChan chan bool
ok bool
lock sync.Mutex
}
func (sess *Session) Close() {
sess.conn.Close()
sess.lock.Lock()
if sess.ok {
sess.ok = false
close(sess.closeNotiChan)
}
sess.lock.Unlock()
}
func (sess *Session) handleRecv() {
defer func() {
sess.Close()
}()
ch := sess.recvChan
header := make([]byte, 2)
for {
/**block until recieve len(header)**/
n, err := io.ReadFull(sess.conn, header)
if n == 0 && err == io.EOF {
//Opposite socket is closed
log.Warn("Socket Read EOF And Close", sess)
break
} else if err != nil {
//Sth wrong with this socket
log.Warn("Socket Wrong:", err)
break
}
//body lenght
size := binary.LittleEndian.Uint16(header) + 4
data := make([]byte, size)
n, err = io.ReadFull(sess.conn, t.Data)
if n == 0 && err == io.EOF {
log.Warn("Socket Read EOF And Close", sess)
break
} else if err != nil {
log.Warn("Socket Wrong:", err)
break
}
ch <- t //#1
}
}
func (sess *Session) handleDispatch() {
defer func() {
sess.Close()
close(sess.recvChan)//#2
for msg := range sess.recvChan {
//do something
}
}()
for {
select {
case msg, ok := <-sess.recvChan:
if ok {
//do something
}
case <-sess.closeNotiChan:
return
}
}
}
func StartClient() {//deal a new connection
var client Session
client.conn = connection
client.recvChan = make(chan []byte, 64)
client.closeNotiChan = make(chan bool)
client.ok = true
go client.handleRecv()
client.handleDispatch()
}
接收数据和调度数据在不同的goroutines.Now我有一个问题。当连接关闭时,会出现数据竞争,#1
和#2
,如下所示(我不发布完整代码)
WARNING: DATA RACE
Write by goroutine 179:
runtime.closechan()
/usr/local/go/src/runtime/chan.go:257 +0x0
sanguo/gameserver.func·004()
/data/mygo/src/sanguo/gameserver/session.go:149 +0xc7
sanguo/gameserver.(*Session).handleDispatch()
/data/mygo/src/sanguo/gameserver/session.go:173 +0x413
sanguo/gameserver.(*Session).Start()
/data/mygo/src/sanguo/gameserver/session.go:223 +0xc6
sanguo/gameserver.handleClient()
/data/mygo/src/sanguo/gameserver/gameserver.go:79 +0x43
Previous read by goroutine 126:
runtime.chansend()
/usr/local/go/src/runtime/chan.go:83 +0x0
sanguo/gameserver.(*Session).handleRecv()
/data/mygo/src/sanguo/gameserver/session.go:140 +0x1171
所以,我的问题是如何在没有“数据竞争”和recvChan
的情况下,如何有效地关闭panic
。
答案 0 :(得分:0)
频道通过发送同步goroutines,但close
上的handleDispatch
本身并未同步。如果您在另一个goroutine通过它发送内容的同时关闭一个频道怎么办?
您应该有另一个频道sess.recvChan
通知&#34;所有者&#34; ({1}}的作者(即作者),即handleRecv
,想要关闭频道。然后handleRecv
应该停止发送并关闭它。
除此之外:我不理解#2
旁边的行:for msg := range sess.recvChan {
如果您刚刚关闭它,您打算从sess.recvChan
到达那里? / p>