github.com/golang-infrastructure/go-reflect-utils@v0.0.0-20221130143747-965ef2eb09c3/channel.go (about) 1 package reflect_utils 2 3 import ( 4 "fmt" 5 "reflect" 6 "unsafe" 7 ) 8 9 // SafeClose 安全的关闭channel,如果已经被关闭的话会recover住panic 10 // 不推荐使用此方法,一个好的结构清晰的代码不应该发生channel被重复关闭的情况,它只会在发送侧关闭一次才对 11 func SafeClose[T any](channel chan T) bool { 12 13 if channel == nil { 14 return true 15 } 16 17 defer func() { 18 _ = recover() 19 }() 20 21 close(channel) 22 return true 23 } 24 25 // IsClosed 判断channel是否已经被关闭 26 func IsClosed[T any](channel chan T) bool { 27 28 // 传入的参数非法的话就认为是已经关闭的channel 29 if channel == nil || reflect.TypeOf(channel).Kind() != reflect.Chan { 30 return true 31 } 32 33 // get interface value pointer, from cgo_export 34 // typedef struct { void *t; void *v; } GoInterface; 35 // then get channel real pointer 36 cptr := *(*uintptr)(unsafe.Pointer( 37 unsafe.Pointer(uintptr(unsafe.Pointer(&channel)) + unsafe.Sizeof(uint(0))), 38 )) 39 40 // this function will return true if chan.closed > 0 41 // see hchan on https://github.com/golang/go/blob/master/src/runtime/chan.go 42 // type hchan struct { 43 // qcount uint // total data in the queue 44 // dataqsiz uint // size of the circular queue 45 // buf unsafe.Pointer // points to an array of dataqsiz elements 46 // elemsize uint16 47 // closed uint32 48 // ** 49 50 // qcount + dataqsiz 51 cptr += unsafe.Sizeof(uint(0)) * 2 52 // buf 53 cptr += unsafe.Sizeof(uintptr(0)) 54 // elemsize 55 cptr += unsafe.Sizeof(uint16(0)) 56 t := unsafe.Pointer(cptr) 57 fmt.Println(t) 58 return *(*uint32)(t) > 0 59 } 60 61