diaa
diaa

Reputation: 328

Stop a goroutine if it is running

I have a question similar to How to stop a goroutine with a small twist. I don't know for sure if the goroutine is running.

var quit = make(chan bool)

func f1() {
    go func() {
        t := time.NewTimer(time.Minute)
        select {
        case <-t.C:
            // Do stuff
        case <-quit:
            return
        }
    }()
}

func f2() {
    quit <- true
}

If f2() is called less than a minute after f1(), then the goroutine returns. However, if it is called later than one minute, the goroutine will have already returned and f2() would block. I want f2() to cancel the goroutine if it is running and do nothing otherwise.

What I'm trying to achieve here is to perform a task if and only if it is not canceled within a minute of creation.

Clarifications:

Upvotes: 2

Views: 3266

Answers (2)

Hymns For Disco
Hymns For Disco

Reputation: 8395

You can give the channel a buffer size of 1. This means you can send one value to it without blocking, even if that value is not received right away (or at all).

var quit = make(chan bool, 1)

I think the top answer is better, this is just another solution that could translate to other situations.

Upvotes: -1

Tyler Kropp
Tyler Kropp

Reputation: 573

Use contexts.

Run f1 with the context which may be cancelled. Run f2 with the associated cancellation function.

func f1(ctx context.Context) {
    go func(ctx context.Context) {
        t := time.NewTimer(time.Minute)
        select {
        case <-t.C:
            // Do stuff
        case <-ctx.Done():
            return
        }
    }(ctx)
}

func f2(cancel context.CancelFunc) {
    cancel()
}

And later, to coordinate the two functions, you would do this:

    ctx, cancel := context.WithCancel(context.Background())
    f1(ctx)
    f2(cancel)

You can also experiment with the context.WithTimeout function to incorporate externally-defined timeouts.

In the case where you don't know whether there is a goroutine running already, you can initialize the ctx and cancel variables like above, but don't pass them into anything. This avoids having to check for nil.

Remember to treat ctx and cancel as variables to be copied, not as references, because you don't want multiple goroutines to share memory - that may cause a race condition.

Upvotes: 10

Related Questions