I'm trying to create a command line quiz, where users would be asked question after question until they either finish the final question, or they are timed out.
I wanted to use channels so I could learn how to use them properly, and I've hit a blocker, so to speak.
The idea is for correctAnswersCh to start with 0, and after every correct answer, it will increment by 1.
The quiz always stops at line 3 of the quiz() function, after I put zero into the channel.
I've added some code below, but the full code is here: https://play.golang.org/p/vzRCTc7MpIK
func main() {
questions, err := getCsvData()
var limit = time.Duration(3)
flag.Parse()
if err != nil {
log.Fatal(err)
}
quizComplete := make(chan bool)
correctAnswersCh := make(chan int)
go quiz(quizComplete, questions, correctAnswersCh)
select {
case <-time.After(limit*time.Second):
fmt.Println("Timed Out")
}
fmt.Printf("Correct Answers: %v\n", <-correctAnswersCh)
}
func quiz(quizComplete chan bool, questions [][]string, correctAnswersCh chan int) {
reader := bufio.NewReader(os.Stdin)
correctAnswersCh <- 0
// execution stops here. 0 is added to correctAnswersCh, then the quiz func stops
for _, question := range questions {
fmt.Print(question[0], "= ")
answer, _ := reader.ReadString('\n')
if strings.TrimSpace(answer) == question[1] {
cA := <-correctAnswersCh
cA++
correctAnswersCh <- cA
}
}
quizComplete <- true
}
Your correctAnswersCh
channel is unbuffered, so sending anything on it blocks until there is someone receiving from it. And since your main()
function only receives from it after the timeout, your app is blocked until then.
One simple workaround is to give 1 buffer to the channel:
correctAnswersCh := make(chan int, 1)
Although this is some weird usage of channels. If your intention is to create a concurrency safe counter, use an aotmic counter, e.g. atomic.AddInt32()
. Another option is to use a mutex (sync.Mutex
or sync.RWMutex
) to protect a resource (variable) when accessed concurrently from multiple goroutines.