Go: question: is it possible to a goroutine immediately stop another goroutine?

Created on 14 Jun 2019  ·  6Comments  ·  Source: golang/go

Taking for example the following code:

package main

import (
    "fmt"
    "time"
    "sync"
)

func secondaryProcess(closeCh chan bool, wg *sync.WaitGroup) {
    for {
        select {
        case _ = <- closeCh:
            fmt.Println("got a close signal")
            wg.Done()
            return
        default:
            fmt.Println("still running")
            time.Sleep(5*time.Second)
        }
    }
}

func main() {
    ch := make(chan bool)
    var wg sync.WaitGroup

    wg.Add(2)
    go func() {
        fmt.Println("going to sleep")
        time.Sleep(1*time.Second)
        fmt.Println("woke up")
        ch <- true
        wg.Done()
    }()
    go secondaryProcess(ch, &wg)

    wg.Wait()
}

(Link for it in the playground)

After sending something in the channel which signals the secondaryProcess to stop, the program will only exit after the Sleep initiated in the default is finished, since it was already started it makes sense that it would be entirely executed. But I could not find a way to immediately stop the execution of the function at a given moment. I tried searching about a way to do this, but after some time reading posts, blogs, etc, it seemed that there's no way to effectively kill a goroutine after it started. Once it begins, it'll run thoroughly until it finishes or encounter an error. So my question is:
Is it possible to completely stop the execution of a goroutine at a given moment, not allowing it to finish it's processing?
If not, was it another behavior that golang purposely choose not to implement?

Most helpful comment

Could you share your solution.

All 6 comments

runtime.Goexit?

I've notice that my question has a certain vagueness, "is it possible to immediately stop a goroutine?", Goexit indeed can terminate a goroutine, but only the one that called it. That's not quite the behavior I'm looking for. What I want is something like goroutine A immediately terminating the execution of goroutine B.
Like, suppose that in my example, the secondaryProcess was just a infinite loop that would do something, sleep for a while and repeat. At some point, the anonymous goroutine in the main would decide to stop that process. The ways I've found to achieve it would either be:

  • signalizing in a channel that the the other routine should stop (but this approach has the problem that it's not immediately terminating the other goroutine, thus it would finalize, possible generating unwanted behavior)
  • make the goroutine that is supposed to be stopped, check a variable after every step of it's execution to be sure it's safe to keep running. Leading to a very messy code with tons of ifs and returns

I'll edit the title of the issue to better reflect the true nature of the question.

Stopping another process, another thread, another goroutine is tricky. The act of saying "operating system stop giving cpu cycles to that thread" sounds simple to achieve, but the results are profound. If the process, thread, or goroutine stops dead in its tracks -- what happens to the resource's it owned? Is the stack unwound? Are defer blocks executed? If so, then the goroutine could continue to live indefinitely as defer blocks run. If defer blocks are not run then that presents the situation where any goroutine can corrupt any invariant of your system by taking a lock, then being shot dead on the spot. There are no suitable answers for these design challenges that do not spawn more questions like "how can I prevent my goroutine from being killed?", etc.

To step back a bit, assuming that there was a mechanism to get a handle on another goroutine, and through that handle stop the goroutine, either unwinding it's stack and executing any defer blocks, or just kicking it out of the scheduler on the spot, what would that allow you to do that you cannot currently do? What is the problem that you are trying to solve by allowing one goroutine to stop another?

The short answer to your question is no, there is no way to do that.

I recommend that you take this to a forum rather than the issue tracker. See https://golang.org/wiki/Questions .

Thank you all for the answers so far.
I'll do as recommended by @ianlancetaylor and take this to the Go Forum. There I'll go into more depth about the problem me and a co-worker though we could solve using this principle. Although we ended up using another solution which was better and far more simple, we remain curious if it would be possible to solve the problem by having a goroutine kill another.

Could you share your solution.

Was this page helpful?
0 / 5 - 0 ratings