源码采用1.9版本;sync包的Cond,条件变量;在我看来,主要是采用他的wait()方法,来控制被阻塞的go程何时去竞争锁;我暂且叫它“双开关控制”(欢迎大神斧正):
废话少说,来个小例子吧:

package main
import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var lc = new(sync.Mutex)
	//这个locker 为啥传入一个引用?
	var cond = sync.NewCond(lc)
	for i := 0; i < 3; i++ {
		go func(x int) {
		   //竞争锁
			cond.L.Lock()
			//记得要释放锁
			defer cond.L.Unlock()
			cond.Wait()
			fmt.Println(x)
		}(i)
	}
	//睡眠一会,确保下面的Signal()能通知到一个(难道可能通知不到?)
	time.Sleep(2*time.Second)
	cond.Signal()
	cond.Broadcast()
	time.Sleep(2*time.Second)
}

运行结果:

0
2
1

上面例子中有两个问题,我们带着问题,查看Cond的一个重要方法:

func (c *Cond) Wait() {
    //检查cond是否被拷贝
	c.checker.check()
	//将获得锁的那个go程加入等待队列
	t := runtime_notifyListAdd(&c.notify)
	//释放锁(可见调用之前要有c.L.lock)
	c.L.Unlock()
	//go程的等待队列等待唤醒,这个操作是阻塞的,除非本go程被唤醒
	runtime_notifyListWait(&c.notify, t)
	//外部记得释放
	c.L.Lock()
}

**为啥传入一个引用?**通过wait方法我看到c.L 的操作,如果不是指针变量,也就是发生锁得拷贝,将导致锁不统一,从而发生死锁;
**难道可能通知不到?**如果不等待至少一个go程加入等待队列,此时调用cond.Signal() 通知,是没有作用的;并且我们发现,go程加入等待队列,需要竞争锁,其实我也没有想明白,为啥要加锁,也许是等待队列的操作是线程不安全的。