Go语言中sync.Cond广播前是否需要先解锁?
Go语言sync.Cond的死锁疑惑解析
先明确sync.Cond的核心行为
- 调用
Cond.Wait()时,会自动释放当前持有的锁,然后进入阻塞状态;当被Broadcast()或Signal()唤醒后,会重新尝试获取锁,只有拿到锁后才会从Wait()返回。这是理解所有问题的基础。
广播前不手动解锁会不会死锁?
分两种情况看:
- 临时阻塞,不算死锁:如果工作goroutine在调用
Broadcast()后,只是继续持有锁执行一些逻辑,之后会主动解锁,那被唤醒的主goroutine只是暂时阻塞在获取锁的步骤,等工作goroutine解锁后就能拿到锁继续执行,这属于正常的锁竞争,不是死锁。 - 真死锁:如果工作goroutine在
Broadcast()后永远不释放锁(比如进入无限循环、panic且没有defer解锁),那被唤醒的主goroutine会一直卡在获取锁的步骤,永远无法继续,这就会造成死锁。
为什么有些代码看起来无需解锁?
你看到的这类代码,大概率是用了defer自动解锁的写法,比如:
func worker(c *sync.Cond) { c.L.Lock() defer c.L.Unlock() // 这里提前声明了defer,goroutine退出时自动解锁 // 修改共享内存 c.Broadcast() // 后续逻辑... }
这种写法里,Broadcast()之后没有显式写Unlock(),但defer会在goroutine退出时自动释放锁,所以看起来像是“无需解锁”,实际上解锁逻辑是存在的。
另外还有一种可能是解锁语句写在Broadcast()之后的代码里,只是位置靠后,容易被忽略。不存在合法的场景可以在广播后不解锁,不解锁的写法属于错误代码,会导致锁资源被永久占用,后续其他需要锁的goroutine都会被阻塞。
内容的提问来源于stack exchange,提问作者jelly
相关产品推荐
相关产品推荐

