如何关闭等待I / O的goroutine

时间:2015-05-30 16:16:21

标签: concurrency go goroutine

我创建了两个例行程序发件人接收器,发件人将连续从用户(键盘)获取数据并写入流,接收器将独立获取值从流打印到屏幕。两者都是并发使用go例程

在某些时候接收器失败并关闭连接以及退出接收器进入例行程序,但是发送器进入等待用户输入(i / o操作)的例程将不会被关闭。如何在这种情况下退出所有go例程?

以下是此方案的示例代码。

package main

import (
    "fmt"
    "time"
)

var stop bool = false

func sender() {
    str := ""
    for !stop {
        fmt.Scanf("%s", &str)
        fmt.Println("Entered :", str)
    }   
    fmt.Println("Closing sender goroutine")
}

func receiver() {
    i := 0
    for !stop {
        i++
        if i > 5 { 
            stop = true
        }
        time.Sleep(1 * time.Second)
    }   
    fmt.Println("Closing receiver goroutine")
}

func main() {
    go sender()
    go receiver()

    /* Wait for goroutines to finish */
    for !stop {
        time.Sleep(1 * time.Millisecond)
    }   
    time.Sleep(1 * time.Second)

    panic("Display stack")
}

上面的代码发送器将在5个循环接收器退出接收器进入例程后等待用户输入。 I expect when receiver close, go routine which waiting on i/o has to be closed.

请帮我解决这个问题。

2 个答案:

答案 0 :(得分:2)

Dave C& JimB说,使用渠道协调goroutines。这是一个可能有帮助的例子。

从用户收到5条消息后退出:

package main

import "fmt"

var pipe = make(chan string) //shares text entered by user
var stop = make(chan bool)   //shares stop signal

func listen() {
    for {
        var input string
        fmt.Scan(&input)
        pipe <- input
    }
}

func write() {
    for i := 0; i < 5; i++ {
        var output string
        output = <-pipe
        fmt.Println("Received", output)
    }

    stop <- true
}

func main() {
    go listen()
    go write()

    <-stop
}

答案 1 :(得分:1)

首先,您的代码围绕stop变量进行竞赛。当存在数据竞争时,无法保证您的程序将按照定义运行。使用通道同步goroutine。但这并不是你继续编程的原因。

您的代码在fmt.Scanf上受阻,并且无法检查stop条件。由于Stdin上的Read不能被中断(发生在fmt.Scanf内),因此您需要在再次调用Scanf之前检查停止条件。如果没有更多的输入,但你有一个待定的Stdin读取,最简单的处理方法就是让goroutine继续运行。有一些相当复杂的方法可以使用被称为“自我管道”的技巧来突破这一点,但它通常不值得努力,因为goroutines很小并且不需要很多资源。

for !stop {
    fmt.Scanf("%s", &str)
    fmt.Println("Entered :", str)
    // use a channel to detect when to exit
    select {
    case <-stop:
        return
    default:
    }
}