duanchi4544 2014-12-26 20:19
浏览 22
已采纳

golang 2 go例程,如果一个终止则终止另一个

so I am using gorillas websocket library and I'm building a websocket server when I receive a connection I create 2 go routines one to read incoming messages from the client and another 1 to listen for in coming messages sent to the channel and then send them to the client.

func (p *Player) EventLoop() {
    l4g.Info("Starting player %s event loop", p)
    go p.readFromSocket()
    go p.writeToSocket()

    //blocks until we receive an interrupt from the read channel
    <-p.closeEventChan
    p.cleanup() //nothing else to do so lets cleanup
}

func (p *Player) writeToSocket() {
    for m := range p.writeChan {
        if p.conn == nil {
            break
        }

        if reflect.DeepEqual(network.Packet{}, m) == true {
            break
        }

        if err := p.conn.WriteJSON(m); err != nil {
            break
        }
    }
    p.closeEventChan <- true
}

func (p *Player) readFromSocket() {
    for {
        if p.conn == nil {
            break
        }

        m := network.Packet{}

        if err := p.conn.ReadJSON(m); err != nil {
            break
        }
    }
    p.closeEventChan <- true
}

func (p *Player) Cleanup() {

    //make sure the channels get a close message which will break us out of the go routines
    close(p.writeChan)
    close(p.closeEventChan)

    //only close the connection if we have a connection
    if p.conn != nil {
        p.conn.Close()
        p.conn = nil
    }
}

my problem is if we leave the readFromSocket() loop Cleanup() is called however we never leave the writeToSocket() loop ! this problem can be simpler demonstrated in this go playground https://play.golang.org/p/49bh7bbbG-

how can we fix this so if we leave the writeToSocket() loop we also leave the readFromSocket() loop and vice vesa?

I was under the impression that this would work as if you call close on a channel (close(p.writeChan)) the default value that the channel accepts will be sent

  • 写回答

1条回答 默认 最新

  • dozrhldy285751 2014-12-27 05:17
    关注

    You can usually do this with a shared quit channel, and some counting.

    func (p *Player) writeToSocket(quit <-chan struct{})
        defer func() {
            p.closeEventChan <- true
        }()
        for {
            select {
            case <-quit:
                return
            case m := <-p.writeChan:
                // Do stuff
            // Case where writeChan is closed, but quit isn't
            default:
                return
            }
        }
    }
    
    
    func (p *Player) readFromSocket(quit <-chan struct{})
        defer func() {
            p.closeEventChan <- true
        }()
        for {
            select {
            case <-quit:
                return
            default:
                // Do stuff
            }
        }
    }
    
    func (p *Player) EventLoop() {
        l4g.Info("Starting player %s event loop", p)
        quit := make(chan struct{})
        go p.readFromSocket(quit)
        go p.writeToSocket(quit)
    
        //blocks until we receive an interrupt from the read channel
        <-p.closeEventChan
        close(quit)
        // This is superfluous here, but in a different case
        // you loop over the remaining number of workers using a NumWorkers variable
        for i := 0; i < 1; i++ {
            <-p.closeEventChan
        }
        p.cleanup() //nothing else to do so lets cleanup
    }
    

    The idea here is that:

    1. All workers notify the central routine upon close via a channel before returning.
    2. All workers return upon a quit message being broadcast (via close).
    3. The central loop closes the quit channel after the first worker exits, then waits for the rest to exit.
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100