-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
The correct formulation for handling for time.Timer.Stop() is error prone and awkward.
What version of Go are you using (go version)?
$ go version go version go1.14.2 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env)?
go env Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/andrew/.cache/go-build" GOENV="/home/andrew/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/andrew/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/home/andrew/src/go/gitea/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build840805710=/tmp/go-build -gno-record-gcc-switches"
What did you do?
In several places in our codebase we create time.Timers. 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() or timer.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.
func (timer *time.Timer) StopAndClear() {
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}
}What did you see instead?
Every time I stop a timer I have to write:
timer := time.Timer(...)
...
if !timer.Stop() {
select {
case <-timer.C:
default:
}
}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
if !t.Stop() {
<-t.C
}write
if !t.Stop() {
select {
case <-t.C:
default:
}
}Thanks so much for the language in general though!