How to check a channel is closed or not without reading it?

I know this answer is so late, I have wrote this solution, Hacking Go run-time, It's not safety, It may crashes:

import (
    "unsafe"
    "reflect"
)


func isChanClosed(ch interface{}) bool {
    if reflect.TypeOf(ch).Kind() != reflect.Chan {
        panic("only channels!")
    }
    
    // get interface value pointer, from cgo_export 
    // typedef struct { void *t; void *v; } GoInterface;
    // then get channel real pointer
    cptr := *(*uintptr)(unsafe.Pointer(
        unsafe.Pointer(uintptr(unsafe.Pointer(&ch)) + unsafe.Sizeof(uint(0))),
    ))
    
    // this function will return true if chan.closed > 0
    // see hchan on https://github.com/golang/go/blob/master/src/runtime/chan.go 
    // type hchan struct {
    // qcount   uint           // total data in the queue
    // dataqsiz uint           // size of the circular queue
    // buf      unsafe.Pointer // points to an array of dataqsiz elements
    // elemsize uint16
    // closed   uint32
    // **
    
    cptr += unsafe.Sizeof(uint(0))*2
    cptr += unsafe.Sizeof(unsafe.Pointer(uintptr(0)))
    cptr += unsafe.Sizeof(uint16(0))
    return *(*uint32)(unsafe.Pointer(cptr)) > 0
}

There's no way to write a safe application where you need to know whether a channel is open without interacting with it.

The best way to do what you're wanting to do is with two channels -- one for the work and one to indicate a desire to change state (as well as the completion of that state change if that's important).

Channels are cheap. Complex design overloading semantics isn't.

[also]

<-time.After(1e9)

is a really confusing and non-obvious way to write

time.Sleep(time.Second)

Keep things simple and everyone (including you) can understand them.


In a hacky way it can be done for channels which one attempts to write to by recovering the raised panic. But you cannot check if a read channel is closed without reading from it.

Either you will

  • eventually read the "true" value from it (v <- c)
  • read the "true" value and 'not closed' indicator (v, ok <- c)
  • read a zero value and the 'closed' indicator (v, ok <- c) (example)
  • will block in the channel read forever (v <- c)

Only the last one technically doesn't read from the channel, but that's of little use.

Tags:

Channel

Go