Go使用sync.Cond时出现all goroutines are asleep死锁原因求解
死锁原因分析
首先明确sync.Cond的核心特性:Cond.Broadcast() 和 Cond.Signal() 发出的信号是一次性无缓冲的,只会唤醒调用信号发送动作时,已经处于Cond.Wait()阻塞状态的goroutine,信号不会被留存给后续才调用Wait()的goroutine。
你注释掉subscribe函数内的sync.WaitGroup相关代码后,死锁的触发时序如下:
- 主goroutine先后调用3次
subscribe函数,每次启动一个处理点击事件的子goroutine后就直接返回,不需要等待子goroutine执行到指定位置 - 3个事件处理子goroutine还没来得及执行到
c.Wait()语句,主goroutine已经先执行了button.Clicked.Broadcast()广播,此时没有处于等待状态的goroutine,这个广播信号直接作废,没有任何效果 - 主goroutine接下来执行
clickRegistered.Wait(),进入阻塞状态,等待3个事件回调执行完毕后调用Done()减计数 - 后续3个事件处理子goroutine先后执行到
c.Wait()语句,进入阻塞状态等待广播/信号,但此前的广播已经发送完成,不会再有新的信号触发它们唤醒,永远不会执行后续的fn()和clickRegistered.Done() - 最终所有goroutine都处于永久阻塞状态,Go运行时检测到没有活跃goroutine,抛出
all go routines are asleep的死锁错误
原本被你注释掉的内部sync.WaitGroup的作用就是做同步保证:每次subscribe调用必须等到对应的子goroutine已经启动、即将进入Wait()阻塞状态时才会返回,这样三次subscribe全部执行完成时,3个事件处理goroutine都已经处于等待状态,后续主goroutine发送的Broadcast才能成功唤醒所有goroutine执行回调,不会出现信号丢失的问题。
内容的提问来源于stack exchange,提问作者madcolonel10
相关产品推荐
相关产品推荐

