I have the following setup:
func startsMain (){
go main ()
}
fun stopMain (){
//kill main
}
func main() {
//infinite loop
}
I am creating cucumber steps and I need to be able to start and shut down the application.
You can kill you infinite loop using select
and channels!
var quit chan struct{}
func startLoop() {
quit := make(chan struct{})
go loop()
}
func stopLoop() {
// As mentioned by Kaedys
//close(quit)
// permits signalling everyone havins such a `case <-quit:`
// statement to be stopped at once, which might be even better.
quit <- struct{}{}
}
// BTW, you cannot call your function main, it is reserved
func loop() {
for {
select {
case <-quit:
return # better than break
default:
// do stuff. I'd call a function, for clarity:
do_stuff()
}
}
}
Nice piece of Go swap, ain't it?
Now, what is this strange chan struct{}
? It is a zero-sized channel. We can only fill it with empty structs (that is: struct{}{}
). It could be a chan bool
or whatever else, since we don't use the content of the channel. The important point is that we use the quit
channel to notify the infinite loop in our goroutine that it is time to stop.
The select
statement is used to catch what comes out of channels. It is a blocking statement (that will halt the execution until something is put in one of the channels surveyed by a case
), unless you put a default
statement. In this situation, every time the select
is executed, the loop will break if something was put inside quit
, or do_stuff()
will be called. You already know this if you've been through the Go Tour.
Other cool concurrency patterns can be found on the Go Blog.
Finally, for further fun, you can ask your do_stuff
function to be executed at regular time intervals by using Ticker
s, instead of consuming 100% CPU, like so:
import "time"
// [...]
func loop() {
// This ticker will put something in its channel every 2s
ticker := time.NewTicker(2 * time.Second)
// If you don't stop it, the ticker will cause memory leaks
defer ticker.Stop()
for {
select {
case <-quit:
return
case <-ticker.C:
// do stuff. I'd call a function, for clarity:
do_stuff()
}
}
}
Here, select
is blocking, since we removed the default
statement.