Skip to content

Instantly share code, notes, and snippets.

@iamatypeofwalrus
Created December 11, 2014 19:31
Show Gist options
  • Select an option

  • Save iamatypeofwalrus/84b6c7d946a6a4143a1d to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

auyer commented Oct 15, 2018

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

@noamnelke
Copy link
Copy Markdown

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
Copy Markdown

Even simpler version, lines 13-18 with:

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

On Playground

@sagarkal
Copy link
Copy Markdown

sagarkal commented Nov 1, 2020

Hi,

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

@noamnelke
Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

πŸ‘πŸ»

@bagardavidyanisntreal
Copy link
Copy Markdown

why not to use atomic.Bool?

@bagardavidyanisntreal
Copy link
Copy Markdown

@noamnelke
Copy link
Copy Markdown

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
Copy Markdown

@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
Copy Markdown

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
Copy Markdown

❀️

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