跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

为什么加了锁的代码偶尔还会导致panic: send on closed channel?

Go语言加锁代码偶尔出现
panic: send on closed channel
的原因分析 在Go语言并发编程中,使用锁(mutex)保证线程安全是常见做法,但即使使用了锁,仍然可能遇到
panic: send on closed channel
错误。本文分析此问题出现的原因及解决方案。 问题代码及现象 以下代码片段演示了该问题:
package main import ( "context" "fmt" "sync" ) var lock sync.Mutex func main() { c := make(chan int, 10) wg := sync.WaitGroup{} ctx, cancel := context.WithCancel(context.Background()) wg.Add(1) go func() { defer wg.Done() lock.Lock() cancel() close(c) lock.Unlock() }() for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { defer wg.Done() select { case c <- i: fmt.Printf("sent %d\n", i) case <-ctx.Done(): fmt.Println("context cancelled") } }(i) } wg.Wait() }
尽管使用了
lock.Lock()
和
lock.Unlock()
保护临界区,但程序仍然可能在
c <- i
处panic,因为
select
语句的非确定性行为。 问题分析 Go语言
select
语句具有非确定性:如果多个case都准备好接收或发送,
select
会随机选择一个执行。 关键在于:
close(c)
和
c <- i
的竞争:
close(c)
操作和
c <- i
操作并非原子操作,存在竞争条件。即使加了锁,
close(c)
操作可能在
c <- i
操作之后执行,导致
c <- i
尝试向已关闭的通道发送数据,从而引发panic。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载
select
语句的随机性: 即使
ctx.Done()
已经准备好,
select
仍然可能随机选择
c <- i
执行。 解决方案 为了避免此问题,需要确保在发送数据前检查通道是否已关闭。 可以使用
select
语句的默认case来实现:
select { case c <- i: fmt.Printf("sent %d\n", i) default: fmt.Println("channel closed or full") }
或者,使用一个额外的通道来协调关闭操作:
package main import ( "fmt" "sync" ) func main() { c := make(chan int, 10) done := make(chan struct{}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() close(done) // Signal that the channel is closing close(c) }() for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { defer wg.Done() select { case c <- i: fmt.Printf("sent %d\n", i) case <-done: fmt.Println("channel closing") } }(i) } wg.Wait() }
这个改进的版本使用
done
通道来通知goroutine通道即将关闭,避免了竞争条件。 通过以上方法,可以有效地避免
panic: send on closed channel
错误,即使在并发环境下使用锁。 选择哪种解决方案取决于具体的应用场景和代码复杂度。

相关文章