Skip to content

Instantly share code, notes, and snippets.

@iamatypeofwalrus
Created December 11, 2014 19:31
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save iamatypeofwalrus/84b6c7d946a6a4143a1d to your computer and use it in GitHub Desktop.
Save iamatypeofwalrus/84b6c7d946a6a4143a1d to your computer and use it in GitHub Desktop.
Check if a Go Channel is open or closed
// An intersting pattern for testing, but you can use the check anywhere
import "testing"
func TestCheckingChannel(t *testing.T) {
stop := make(chan bool)
// Testing some fucntion that SHOULD close the channel
func (stop chan bool) {
close(chan)
}(stop)
// Make sure that the function does close the channel
_, ok := (<-stop)
// If we can recieve on the channel then it is NOT closed
if ok {
t.Error("Channel is not closed")
}
}
@auyer
Copy link

auyer commented Oct 15, 2018

Line 9 should be close(stop) instead of close(chan)

@noamnelke
Copy link

The error will never occur. If the channel isn't closed the function will block forever on line 13.

It would work if you replaced line 13 with the following:

	ok := true
	select {
	case _, ok = <-stop:
	default:
	}

A select with a default clause is a non-blocking read from the channel.

POC on Go Playground

@noamnelke
Copy link

Even simpler version, lines 13-18 with:

	select {
	case <-stop:
	default:
		t.Error("Channel is not closed")
	}

On Playground

@sagarkal
Copy link

sagarkal commented Nov 1, 2020

Hi,

I don't understand why the default clause is also needed..

@noamnelke
Copy link

A select with no default will block until one of the channels yields something.

Adding a default clause ensures the select never blocks, so either the channel is closed and that case materializes (nothing happens) or the default materializes and an error is registered.

@sagarkal
Copy link

sagarkal commented Nov 2, 2020

A select with no default will block until one of the channels yields something.

Adding a default clause ensures the select never blocks, so either the channel is closed and that case materializes (nothing happens) or the default materializes and an error is registered.

Got it thanks Noam!

@noamnelke
Copy link

The assignment is never blocking, the read from the channel is blocking. The reason it looks non-blocking to you is that the channel is always closed by the time the read operation is performed.

Try to run the function closing the channel in a go routine (just add the keyword go at the start of line 11). In my code you'll get the result:

channel was NOT closed

While in your case you'll still get:

Result is: false

The loop you added isn't needed, as it always runs exactly once. If the channel is closed already, it'll go into the if and break out of the loop. If the channel isn't closed (if you added the go to line 11), it will block on line 19 until the channel is closed and then break out fo the loop.

@Jeevesh8
Copy link

Jeevesh8 commented Mar 8, 2021

Yes, I understood. That's why I deleted my comment. But you already replied. Sorry. And thank you 😄

@noamnelke
Copy link

👍🏻

@bagardavidyanisntreal
Copy link

why not to use atomic.Bool?

@bagardavidyanisntreal
Copy link

@noamnelke
Copy link

I have to admit that I didn't understand all of your code in the playground, but it seems more complex and slower. It also doesn't do what the original intent of this gist is: which I interpret as reading from a channel in a non-blocking way.

General remark: I don't think it's a good idea to overload the built-in close function (the only way to close a channel).

@bagardavidyanisntreal
Copy link

@noamnelke I have never heard about overload in Go. the close func in this gist is just a Closer implementation

I didn't understand all of your code

so sad

@mrtdeh
Copy link

mrtdeh commented Jan 30, 2024

The error will never occur. If the channel isn't closed the function will block forever on line 13.

It would work if you replaced line 13 with the following:

	ok := true
	select {
	case _, ok = <-stop:
	default:
	}

A select with a default clause is a non-blocking read from the channel.

POC on Go Playground

Thanks , you save my day.

@noamnelke
Copy link

❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment