gpt4 book ai didi

go - 如何优雅的关闭 channel ?

转载 作者:IT王子 更新时间:2023-10-29 02:24:07 25 4
gpt4 key购买 nike

我有一个服务器,它像这样处理连接 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中。现在我有一个问题。当连接关闭时,会出现数据竞争,#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

最佳答案

Channels 通过发送来同步 goroutines,但是它们的 close 本身并不同步。如果您在另一个 goroutine 正在通过它发送内容的同时关闭一个 channel 怎么办?

你应该有另一个 channel ,通过它 handleDispatch 通知 sess.recvChan 的“所有者”(即作者),即 handleRecv ,它想要关闭 channel 。然后 handleRecv 应该停止从它发送并关闭它。

除此之外:我不明白 #2 旁边的行:for msg := range sess.recvChan { 你想从那里得到什么sess.recvChan,如果你刚刚关闭它呢?

关于go - 如何优雅的关闭 channel ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28149682/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com