源码采用1.9版本;sync包的Cond,条件变量;在我看来,主要是采用他的wait()方法,来控制被阻塞的go程何时去竞争锁;我暂且叫它“双开关控制”(欢迎大神斧正):
废话少说,来个小例子吧:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var lc = new()
//这个locker 为啥传入一个引用?
var cond = (lc)
for i := 0; i < 3; i++ {
go func(x int) {
//竞争锁
()
//记得要释放锁
defer ()
()
(x)
}(i)
}
//睡眠一会,确保下面的Signal()能通知到一个(难道可能通知不到?)
(2*)
()
()
(2*)
}
运行结果:
0
2
1
上面例子中有两个问题,我们带着问题,查看Cond的一个重要方法:
func (c *Cond) Wait() {
//检查cond是否被拷贝
()
//将获得锁的那个go程加入等待队列
t := runtime_notifyListAdd(&)
//释放锁(可见调用之前要有)
()
//go程的等待队列等待唤醒,这个操作是阻塞的,除非本go程被唤醒
runtime_notifyListWait(&, t)
//外部记得释放
()
}
**为啥传入一个引用?**通过wait方法我看到 的操作,如果不是指针变量,也就是发生锁得拷贝,将导致锁不统一,从而发生死锁;
**难道可能通知不到?**如果不等待至少一个go程加入等待队列,此时调用() 通知,是没有作用的;并且我们发现,go程加入等待队列,需要竞争锁,其实我也没有想明白,为啥要加锁,也许是等待队列的操作是线程不安全的。