Below is a function that starts an external process, matches a regular expression against the process' standard output, and returns the contents of the match.
func (c *Colony) startCircuit(peer *string) (string, error) {
var (
err error
cmd *exec.Cmd
anchorChan chan string
)
// ... (omitted for readability)
// get the anchor from standard output
go func() {
defer out.Close()
anchorChan = make(chan string)
for scanner := bufio.NewScanner(out); scanner.Scan(); {
line := scanner.Text()
if anchor := reRootAnchor.FindString(line); anchor != "" {
log.Println("Started circuit server with anchor:", anchor)
anchorChan <- anchor
break
}
}
}()
anchor := <-anchorChan
return anchor, err
}
When running the function, I obtain the following output, which shows that a match is indeed found and (presumably) pushed into anchorChan
:
2016/05/22 14:04:36 Started circuit server with anchor: circuit://[::]:36195/20666/Q431cc5fe613aa04b
However, startCircuit
's caller seems to hang. Here is the relevant bit of code:
rootAnchor, err := c.startCircuit(peer)
if err != nil {
return "", err
}
log.Fatal(rootAnchor) // DEBUG
Why is startCircuit
hanging indefinitely instead of returning?
The problem is in fact quite simple. Hint: the following code ends in a deadlock.
package main
import "fmt"
func main() {
var c chan string
go func() {
c = make(chan string)
c <- "42"
}()
str := <-c
fmt.Println(str)
}
From there, the problem is trivial. Your channel is not initialized when you start the goroutine. There is a race with the two goroutines, and apparently go cannot decide which should have the priority.
So, your answer is: call make(chan ...)
before the goroutine starts, it should solve your problem. There is a perfect example of this in effective go.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments