两个例程从同一频道读取。在done
频道关闭后,第一个例程从不打印关闭消息,而第二个例程总是这样做。
为什么来自第一个例程的消息不打印,方法是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()
}
}
}
}
答案 0 :(得分:2)
原因是因为你已经创建了同步频道,你在这里推送了1条消息,然后你也只能阅读它一次。这是因为您只从done
频道获得了1次(随机)阅读。
关闭goroutine的方法是使用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
........
}
}
}
使用此link了解详情
答案 1 :(得分:0)
UserInputListener
未进入case <-done:
的原因是因为它等待此行的某些输入而停滞不前:
line, _, err := reader.ReadLine()
此行正在阻止!
这并不容易。
您可以使用另一个例行程序进行阅读,将数据发送到您从done
频道中读取的选择中读取的频道。这将正确关闭UserInputListener
,但让另一个goroutine不能正常关闭。但也许这并不重要......?
func (o *Operator) UserInputListener(done <-chan bool) {
// channel with some buffer so reader doesn't have to wait (so much)
ch := make(chan string, 10)
go func() {
reader := bufio.NewReader(os.Stdin)
for {
line, _, err := reader.ReadLine()
if err != nil {
log.Println(err)
// stop on error?
// return
}
ch <- string(line)
}
}()
for {
select {
case <-done:
log.Println("Keyboard listener shutting down.") // <-- this never prints
return
case line:= <-ch:
data := strings.Split(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",
}
}
}
}
}
您也可以尝试关闭reader
正在读取的内容。我已经在其他环境中使用过此解决方案,例如从串行设备读取。
这不适用于os.Stdin
,但正如JimB指出的那样。 os.StdIn.Close()
会在等待读者完成时阻止。