package main import ( "fmt" "sync" "time" ) /** * Cond 当协程 */ func main() { var lc = new(sync.Mutex) //这个locker 为啥传入一个引用? var cond = sync.NewCond(lc) for i := 0; i < 5; i++ { go func(x int) { cond.L.Lock() defer cond.L.Unlock() cond.Wait() fmt.Printf("value is %d\n",x) }(i) } //睡眠一会,确保下面的Signal()能通知到一个(难道可能通知不到?) time.Sleep(2*time.Second) for i:=0;i<3;i++{ fmt.Printf("唤醒第%d个go程\n",i) cond.Signal() time.Sleep(time.Second*1) } fmt.Println("全部唤醒") cond.Broadcast() time.Sleep(2*time.Second) }
//-----------------------结果是------------------------
唤醒第0个go程
value is 1
唤醒第1个go程
value is 0
唤醒第2个go程
value is 3
全部唤醒
value is 2
value is 4
Cond在go程中,分别的获取了锁并处于等待状态,为什么他能够在go程中都获取一个内存锁,这个需要看go语言的内存设计。
分别获取锁之调用Wait()进入等待队列。
func (c *Cond) Wait() {//Wait操作的是指针,指向的是内存 c.checker.check() t := runtime_notifyListAdd(&c.notify)//见名知道意思,将Cond的可唤醒属性加入可唤醒队列中 c.L.Unlock()//这里进行短暂时的释放,并把Cond的关键属性的指针放入等待队列中, runtime_notifyListWait(&c.notify, t) c.L.Lock() }
对这里为什么需要进行锁释放的理解:进入运行时等待的不能是一个持有了锁的携程?????
func (c *copyChecker) check() {//这个checker作用是对c的指针以及值引用的地址是一样的,如果步一样就说明被复制了。 if uintptr(*c) != uintptr(unsafe.Pointer(c)) && !atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) && uintptr(*c) != uintptr(unsafe.Pointer(c)) { panic("sync.Cond is copied") } }
Signl的过程与Broadcast的过程,都是使用同一个指针指示调用的运行时的方法,更能证明他们使用的是同一个指针作为标记进行等待存储。至于他为什么能有如此效果,需要后续开发。