go条件变量sync.Cond的使用和思考

源码采用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() }

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

    推荐阅读