doupai5450 2018-12-27 16:04
浏览 24
已采纳

如何有效地关闭两个goroutines?

I'm using two concurrent goroutines to copy stdin/stdout from my terminal to a net.Conn target. For some reason, I can't manage to completely stop the two go routines without getting a panic error (for trying to close a closed connection). This is my code:

func interact(c net.Conn, sessionMap map[int]net.Conn) {
    quit := make(chan bool) //the channel to quit

    copy := func(r io.ReadCloser, w io.WriteCloser) {
        defer func() {
            r.Close()
            w.Close()
            close(quit) //this is how i'm trying to close it
        }()

        _, err := io.Copy(w, r)

        if err != nil {
            //
        }

    }

    go func() {
        for {
            select {
            case <-quit:
                return
            default:
                copy(c, os.Stdout)
            }
        }
    }()

    go func() {
        for {
            select {
            case <-quit:
                return
            default:
                copy(os.Stdin, c)
            }
        }
    }()
}

This errors as panic: close of closed channel I want to terminate the two go routines, and then normally proceed to another function. What am I doing wrong?

  • 写回答

2条回答 默认 最新

  • dougou5852 2018-12-27 16:27
    关注

    You can't call close on a channel more than once, there's no reason to call copy in a for loop, since it can only operate one time, and you're copying in the wrong direction, writing to stdin and reading from stdout.

    Simply asking how to quit 2 goroutines is simple, but that's not the only thing you need to do here. Since io.Copy is blocking, you don't need the extra synchronization to determine when the call is complete. This lets you simplify the code significantly, which will make it a lot easier to reason about.

    func interact(c net.Conn) {
        go func() {
            // You want to close this outside the goroutine if you
            // expect to send data back over a half-closed connection
            defer c.Close()
    
            // Optionally close stdout here if you need to signal the
            // end of the stream in a pipeline.
            defer os.Stdout.Close()
    
            _, err := io.Copy(os.Stdout, c)
            if err != nil {
                //
            }
        }()
    
        _, err := io.Copy(c, os.Stdin)
        if err != nil {
            //
        }
    }
    

    Also note that you may not be able to break out of the io.Copy from stdin, so you can't expect the interact function to return. Manually doing the io.Copy in the function body and checking for a half-closed connection on every loop may be a good idea, then you can break out sooner and ensure that you fully close the net.Conn.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 nginx反向代理获取ip,java获取真实ip
  • ¥15 eda:门禁系统设计
  • ¥50 如何使用js去调用vscode-js-debugger的方法去调试网页
  • ¥15 376.1电表主站通信协议下发指令全被否认问题
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥15 复杂网络,变滞后传递熵,FDA
  • ¥20 csv格式数据集预处理及模型选择
  • ¥15 部分网页页面无法显示!
  • ¥15 怎样解决power bi 中设置管理聚合,详细信息表和详细信息列显示灰色,而不能选择相应的内容呢?
  • ¥15 QTOF MSE数据分析