dongya6395 2017-08-08 14:53
浏览 16
已采纳

goroutine关闭频道`done'后不打印`shutdown message`

Two go routines reading from the same channel. The first go routine never prints its shutdown message after the done channel is closed, while the second go routine always does.

Why is the message from the first go routine not printing and is the method even returning?

main.go

func main() {
done := make(chan bool)
c := make(chan os.Signal, 1)

cameras := client.CameraConfig()
client.DrawUserControls(cameras)

operator := client.NewOperator(cameras)
go operator.UserInputListener(done)
go operator.ParseAndExecuteUserCommand(done)

signal.Notify(c, os.Interrupt)
for range c {
    close(done)
    break
}

log.Println("Interrupt signal received. Shutting client down....")
time.Sleep(5 * time.Second)
}

client.go

func (o *Operator) UserInputListener(done <-chan bool) {
    reader := bufio.NewReader(os.Stdin)
    for {
        select {
        case <-done:
            log.Println("Keyboard listener shutting down.") // <-- this never prints
            return
        default:
            line, _, err := reader.ReadLine()
            if err != nil {
                log.Println(err)
            }

            data := strings.Split(string(line), "")

            id, err := strconv.Atoi(data[1])
            if err != nil {
                log.Println(err)
                continue
            }

            switch data[0] {
            case "b":
                o.Controls <- Ctrl{
                    Identifier: id,
                    Ctrl:       "run",
                }
            case "t":
                o.Controls <- Ctrl{
                    Identifier: id,
                    Ctrl:       "terminate",
                }
            case "r":
                o.Controls <- Ctrl{
                    Identifier: id,
                    Ctrl:       "record",
                }
            case "s":
                o.Controls <- Ctrl{
                    Identifier: id,
                    Ctrl:       "stop",
                }
            }
        }
    }
}

func (o *Operator) ParseAndExecuteUserCommand(done <-chan bool) {
    for {
        select {
        case <-done:
            log.Println("Command operator shutting down.")
            return
        case ctrl := <-o.Controls:
            switch ctrl.Ctrl {
            case "run":
                o.Room[ctrl.Identifier].Run()
            case "terminate":
                o.Room[ctrl.Identifier].Close()
            case "record":
                o.Room[ctrl.Identifier].Write()
            case "stop":
                o.Room[ctrl.Identifier].Stop()
            }
        }
    }
}
  • 写回答

2条回答 默认 最新

  • douyao7390 2017-08-08 16:55
    关注

    The reason is because you have created synchronous channel and you push here 1 message and then you could read it only once as well. That is because you get only 1 (random) read from done channel.

    The way you can shut down your goroutines is to use WaitGroup:
    main.go:

    var (
        done            chan bool
    )
    
    func main() {
        cameras := client.CameraConfig()
        client.DrawUserControls(cameras)
        operator := client.NewOperator(cameras)
    
        done = make(chan bool, 1)
        wg := &sync.WaitGroup{}
        wg.Add(2)
        go operator.UserInputListener(done, wg)
        go operator.ParseAndExecuteUserCommand(done, wg)
    
        handleShutdown()
        wg.Wait()
    }
    
    
    func handleShutdown() {
        ch := make(chan os.Signal, 1)
        go func() {
            <-ch //wait for application terminating
            log.Println("Shutdown received.")
            close(done)
        }()
        signal.Notify(ch, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
    }
    

    client.go:

    func (o *Operator) UserInputListener(done <-chan bool, wg *sync.WaitGroup) {
        defer wg.Done()
        for {
            select {
            case <-done:
                log.Println("Keyboard listener shutting down.") 
                return
            ........
            }
        }
    }
    
    func (o *Operator) ParseAndExecuteUserCommand(done <-chan bool, wg *sync.WaitGroup) {
        defer wg.Done()
        for {
            select {
            case <-done:
                log.Println("Command operator shutting down.") 
                return
            ........
            }
        }
    }
    

    Use this link for details

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

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?