Skip to content
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

Deadlock wenn stopping stopped timer #18553

Closed
nefthy opened this issue Jan 7, 2017 · 3 comments
Closed

Deadlock wenn stopping stopped timer #18553

nefthy opened this issue Jan 7, 2017 · 3 comments

Comments

@nefthy
Copy link

nefthy commented Jan 7, 2017

What version of Go are you using (go version)?

go version devel +116da1c Fri Jan 6 20:55:48 2017 +0000 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/nefthy/go-test/"
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="x86_64-pc-linux-gnu-gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/home/nefthy/go-test/tmp/go-build490756288=/tmp/go-build -gno-record-gcc-switches"
CXX="x86_64-pc-linux-gnu-g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"

What did you do?

	t := time.NewTimer(time.Second * 10)
	if !t.Stop() {
		_, ok := <-t.C
	}
	if !t.Stop() {
		_, ok := <-t.C
	}
        fmt.Println("OK")

full playground example

What did you expect to see?

 //Output: OK

According to Spec _, ok := <-t.C will not block, but set ok to false. The Docs for Stop() also suggest using:

if !t.Stop() {
	<-t.C
}

And mentions the case of the timer is stopped, so I expect this to work when the timer has already been stopped.

What did you see instead?

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.Brocken()
/tmp/sandbox409514762/main.go:42 +0x5a0
main.main()
/tmp/sandbox409514762/main.go:50 +0x40

@titanous
Copy link
Member

titanous commented Jan 7, 2017

The documentation says:

Stop prevents the Timer from firing. It returns true if the call stops the timer, false if the timer has already expired or been stopped. Stop does not close the channel, to prevent a read from the channel succeeding incorrectly.

The bool from Stop will tell you if the timer was stopped by the call, so in your example the second call of Stop will return false because the timer had already been stopped and your code will block forever (deadlock) because the channel was not closed (as documented) and the timer will not fire (as documented).

This is working as intended.

@titanous titanous closed this as completed Jan 7, 2017
@nefthy
Copy link
Author

nefthy commented Jan 7, 2017

you are absolutely right about this. thanks.

May I still suggest updtating the example in the documentation to something along the lines:

if !t.Stop() {
	<-t.C
        //call close(t.C) if you no longer need it
}

@ianlancetaylor
Copy link
Member

Thanks for the suggestion, but in general there is no need to close an unneeded channel. A channel only needs to be closed if there is some other goroutine waiting to read from the channel and checking whether it has been closed, as in a for/range statement. I don't think the comment in the time package needs to be updated.

@golang golang locked and limited conversation to collaborators Jan 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants