-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: time: Timer.StopAndClear method #38945
Comments
I'm concerned that this might be a bit of a footgun, since correct behavior really depends on whether there are any other goroutines also reading from the channel. If you know for sure that there are no other goroutines reading, then the code in https://golang.org/pkg/time/#Timer.Stop is correct: if !t.Stop() {
<-t.C
} If there are other goroutines reading from the channel, then it's not completely obvious what the right code is. At least, it's not obvious to me. Just to be very clear, there is no need to read from the channel after calling |
Note that if !t.Stop() {
select {
case <-t.C:
default:
}
} is not entirely reliable today (with or without concurrent receivers) due to #37196. (If that issue is addressed, then that pattern will be correct even in the presence of concurrent receivers.) |
I'm not sure that StopAndClear has any possible benefit. At first it might seem like it does, but the details of concurrency and channels and goroutines make the situation more subtle than it first appears. If another goroutine is waiting to read a value from a channel, then t.StopAndClear would race with it. The t.StopAndClear call could return but then the other goroutine could still - in physical wall time - receive the value afterward, due to scheduling delays. You need some explicit synchronization with the other goroutine to make sure that processing of the receive is over. But if you are going to that trouble (or you don't have the other goroutine) then t.Stop is sufficient. So t.StopAndClear doesn't end up being any easier to use than t.Stop. The one thing t.StopAndClear could do is solve the "time value waiting in a buffered channel" issue. But if we want to fix that, we should probably just make t.Stop do that part, instead of adding new API. That's #37196 (thanks Bryan), which we can discuss over there. |
Based on the discussion above, this seems like a likely decline. |
Yeah it looks like I was confused by the documentation - it's nice to know that we don't need to clear channels to prevent leaks. |
No change in consensus (and retracted), so marking declined. |
The correct formulation for handling for
time.Timer.Stop()
is error prone and awkward.What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
In several places in our codebase we create
time.Timer
s. The problem is that handling the timer stop condition is not obvious to the beginning user and, even for those who know to clear the channel the correct incantation is errorprone (do I potentially need to clear the channel!timer.Stop()
ortimer.Stop()
) and is needlessly repetitive.What did you expect to see?
There should be a simple function that will stop and clear the channel for the timer.
e.g.
What did you see instead?
Every time I stop a timer I have to write:
to ensure that the channel does not leak. I also have to remember that the block has to activate when not stopped. Reviewers of code have to all be aware of this too.
It seems to be a needless gotcha that could be handled relatively nicely in the standard library.
I would also advise that the formulation in the standard library documentation is also changed as it encourages the naïve user to cause a deadlock:
i.e. instead of
write
Thanks so much for the language in general though!
The text was updated successfully, but these errors were encountered: