How do I kill a goroutine

Issue

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.

Solution

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 Tickers, 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.

Answered By – Adrien Luxey

Answer Checked By – Senaida (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.