So I have this code, it accepts user entry of one
, two
, or three
. It prints Ticker ticked
depending on the duration selected. I need help on how to stop the ticker first before activating the ticker again with a different duration.
package main
import (
"bufio"
"fmt"
"os"
"strings"
"time"
)
func main() {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("> ")
text, _ := reader.ReadString('
')
text = strings.Replace(text, "
", "", -1)
switch text {
case "one":
go timeTick(true, 1)
case "two":
go timeTick(true, 2)
case "three":
go timeTick(true, 3)
default:
go timeTick(false, 0)
}
}
}
func timeTick(flag bool, tick int) {
var tickChan *time.Ticker
if flag {
tickChan = time.NewTicker(time.Second * time.Duration(tick))
}
doneChan := make(chan bool)
if !flag {
doneChan <- true
}
for {
select {
case <-tickChan.C:
fmt.Println("Ticker ticked")
case <-doneChan:
fmt.Println("Done")
return
}
}
}
So user inputs either, one
, two
, or three
to activate the ticker else it will send true
to doneChan
channel.
When I activated the ticker with one
. It prints Ticker ticked
every second but how do I stop the ticker when I input two
or three
while the ticker is running? It then brings me to my main question, why is doneChan
not triggered at all even inputting a random string?
You need to pass in the channel used to signal completion. You always want to cancel the current ticker if there is one, so you can attempt a send in each iteration of the main for
loop. Since the channel isn't buffered, a send operation is blocking, so you need to attempt the send in a select statement with a default case to prevent a deadlock in the case you don't have a current ticker attempting to read from the channel.
package main
import (
"bufio"
"fmt"
"os"
"strings"
"time"
)
func main() {
reader := bufio.NewReader(os.Stdin)
tickerDone := make(chan struct{})
for {
fmt.Print("> ")
text, _ := reader.ReadString('
')
text = strings.Replace(text, "
", "", -1)
select {
case tickerDone <- struct{}{}:
default:
}
switch text {
case "one":
go timeTick(1, tickerDone)
case "two":
go timeTick(2, tickerDone)
case "three":
go timeTick(3, tickerDone)
}
}
}
func timeTick(tick int, done <-chan struct{}) {
tickChan := time.NewTicker(time.Second * time.Duration(tick))
for {
select {
case <-tickChan.C:
fmt.Println("Ticker ticked")
case <-done:
fmt.Println("Done")
return
}
}
}
You can try this code below also. I put buffered channel outside the function for synchronize execution, I also used channel receiver to assign and to stop channel.
func timeTick(flag bool, tick int,doneChan chan bool) {
var tickChan *time.Ticker
msg := make(<-chan time.Time) // channel receiver
if flag {
tickChan = time.NewTicker(time.Second * time.Duration(tick))
}
if !flag {
doneChan <- true
<-msg
}
if tickChan != nil { // Check if nil
msg = tickChan.C
}
for {
select {
case <-msg:
fmt.Println("Ticker ticked ")
case <-doneChan:
fmt.Println("Done ")
return
}
}
}
func main() {
reader := bufio.NewReader(os.Stdin)
doneChan := make(chan bool,1)
for
{
fmt.Print("> ")
text, _ := reader.ReadString('
')
text = strings.Replace(text, "
", "", -1)
switch text {
case "one":
go timeTick(true, 1, doneChan)
case "two":
go timeTick(true, 2, doneChan)
case "three":
go timeTick(true, 3, doneChan)
default:
go timeTick(false, 0, doneChan)
}
}
}