28 | 条件变量sync.Cond (下)
问题 1:条件变量的Wait方法做了什么?
在了解了条件变量的使用方式之后,你可能会有这么几个疑问。
1、为什么先要锁定条件变量基于的互斥锁,才能调用它的Wait方法?
2、为什么要用for语句来包裹调用其Wait方法的表达式,用if语句不行吗?
这些问题我在面试的时候也经常问。你需要对这个Wait方法的内部机制有所了解才能回答上来。
条件变量的Wait方法主要做了四件事。
1、把调用它的 goroutine(也就是当前的 goroutine)加入到当前条件变量的通知队列中。
2、解锁当前的条件变量基于的那个互斥锁。
3、让当前的 goroutine 处于等待状态,等到通知到来时再决定是否唤醒它。此时,这个 goroutine 就会阻塞在调用这个Wait方法的那行代码上。
4、如果通知到来并且决定唤醒这个 goroutine,那么就在唤醒它之后重新锁定当前条件变量基于的互斥锁。自此之后,当前的 goroutine 就会继续执行后面的代码了。
你现在知道我刚刚说的第一个疑问的答案了吗?
因为条件变量的Wait方法在阻塞当前的 goroutine 之前,会解锁它基于的互斥锁,所以在调用该Wait方法之前,我们必须先锁定那个互斥锁,否则在调用这个Wait方法时,就会引发一个不可恢复的 panic。
为什么条件变量的Wait方法要这么做呢?你可以想象一下,如果Wait方法在互斥锁已经锁定的情况下,阻塞了当前的 goroutine,那么又由谁来解锁呢?别的 goroutine 吗?
先不说这违背了互斥锁的重要使用原则,即:成对的锁定和解锁,就算别的 goroutine 可以来解锁,那万一解锁重复了怎么办?由此引发的 panic 可是无法恢复的。
如果当前的 goroutine 无法解锁,别的 goroutine 也都不来解锁,那么又由谁来进入临界区,并改变共享资源的状态呢?只要共享资源的状态不变,即使当前的 goroutine 因收到通知而被唤醒&#x