对于closed或nil通道,规则如下:
- 无论收发,nil通道都会阻塞。
- 不能关闭nil通道。
- 重复关闭通道,引发panic !
- 向已关闭通道发送数据,引发 panic!
- 从已关闭通道接收数据,返回缓冲数据或零值。
nil通道是指没有make的变量。鉴于通道关闭后,所有基于此的阻塞都被解除,可用作通知。
没有判断通道是否已被关闭的直接方法,只能透过收发模式获知,
操作 | 已关闭的channel | nil channel |
---|---|---|
读 | 如果channel中还有数据,可以继续读取;如果channel中没有数据了, 可以读到零值 | 永久阻塞(deadlock) |
写 | panic: send on closed channel | 永久阻塞(deadlock) |
close | panic: close of closed channel | panic: close of nil channel |
为避免重复关闭,可包装close函数。也可以类似方式封装send recv 操作。
func closechan[T any](c chan T) {
defer func(){
recover()
}()
close(c)
}
func main() {
c := make(chan int, 2)
closechan(c)
closechan(c)
}
可使用 sync.RWMutex、sync.Once 优化设计。
type Queue[T any] struct {
sync.Mutex
ch chan T
cap int
closed bool
}
func NewQueue[T any](cap int) *Queue[T] {
return &Queue[T]{
ch: make(chan T, cap),
}
}
func (q *Queue[T]) Close() {
q.Lock()
defer q.Unlock()
if !q.closed {
close(q.ch)
q.closed = true
}
}
func (q *Queue[T]) IsClosed() bool {
q.Lock()
defer q.Unlock()
return q.closed
}
// ---------------------------------
func main() {
var wg sync.WaitGroup
q := NewQueue[int](3)
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
defer q.Close()
println(q.IsClosed())
}()
}
wg.Wait()
}
利用 nil 通道阻止退出。
func main() {
<-(chan struct{})(nil) // select{}
}
标签:封装,closed,nil,golang,func,close,channel,通道 From: https://www.cnblogs.com/codestack/p/18187366