记录一次[panic: send on closed channel]错误
主线程创建并初始化 channel ,开启多线程操作 k8s 创建 pvc、pv,主线程阻塞;程序在线程 xx 中创建 pvc 失败,线程报错,将错误信息输入到 channel 中,主线程接收到 channel 并报错。
·
出现场景
主线程创建并初始化 channel ,开启多线程操作 k8s 创建 pvc、pv,主线程阻塞;程序在线程 xx 中创建 pvc 失败,线程报错,将错误信息输入到 channel 中,主线程接收到 channel 并报错panic: send on closed channel [recovered] panic: send on closed channel
简化代码
package main
import (
"errors"
"fmt"
"time"
)
func main() {
test()
// 主线程阻塞,防止主线程过早结束
select {}
}
func test() error {
strChan := make(chan string)
defer close(strChan)
for i := 0; i < 2; i++ {
tmp := i
go func(i int) {
defer func() {
if err := recover(); err != nil {
fmt.Println("recover...")
strChan <- "revocer 检测到错误"
return
}
}()
if i == 1 {
time.Sleep(2 * time.Second)
}
strChan <- fmt.Sprintf("i am %v goroutine", i)
return
}(tmp)
}
select {
case a := <-strChan:
if a != "" {
return errors.New("检测到管道中数据,停止阻塞")
}
}
fmt.Println(<-strChan)
return nil
}
原因分析
主线程使用 for 循环开启两个协程,假设为协程 0、1,
执行协程 0,将“i am 0 goroutine”字符串输入到 strChan 中,
执行协程 1,协程1等待2秒钟后执行上述操作,
主线程执行 select 阻塞等待,此时协程0将数据输入到管道 strChan 中,
主线程中的 case a := <-strChan
接收到数据,准备执行 return 操作,在执行 return 之前程序会先执行 defer close(strChan)
关闭通道,
所以,协程0执行完毕以后 strChan 管道已经被关闭。
两秒钟以后协程1往 strChan 中输入数据,此时管道已关闭,发生 panic 错误并被 recover 检测到。
总结:
多个线程之间存在时间差,有的线程过早执行完毕触发代码的关闭管道操作,导致程序发生 panic。
更多推荐
已为社区贡献2条内容
所有评论(0)