Go并发之sync中Cond

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的过程,都是使用同一个指针指示调用的运行时的方法,更能证明他们使用的是同一个指针作为标记进行等待存储。至于他为什么能有如此效果,需要后续开发。

猜你喜欢

转载自blog.csdn.net/weixin_40669549/article/details/88544181