> 文档中心 > golang并发编程-05-同步-02-条件变量(Cond结构体的常用方法)

golang并发编程-05-同步-02-条件变量(Cond结构体的常用方法)

文章目录

  • 1. sync.Cond结构体
  • 2. sync.Cond结构体常用方法
  • 3. 使用示例
    • 3.1 示例(蜀军的作战会议——广播唤醒)
    • 3.2 示例(蜀军薪资调整了——单独唤醒)

1. sync.Cond结构体

  • 结构体定义
type Cond struct {    noCopy  noCopy    LLocker    notify  notifyList    checker copyChecker}
  • 作用
    实现了一个条件变量,用于等待一个或一组协程满足条件后唤醒这些协程。

从结构体定义可知,每个Cond关联一个Locker(*Mutex或*RWMutex)。

2. sync.Cond结构体常用方法

  • NewCond 创建实例
cadence := sync.NewCond(&sync.Mutex{})
  • 广播唤醒所有
go func() {   for range time.Tick(1 * time.Millisecond) {      cadence.Broadcast()   }}()
  • 唤醒一个协程
go func() {   for range time.Tick(1 * time.Millisecond) {      cadence.Signal()   }}()
  • 等待
c.L.Lock()for !condition() {    c.Wait()}... make use of condition ...c.L.Unlock()

3. 使用示例

3.1 示例(蜀军的作战会议——广播唤醒)

package mainimport ("fmt""sync""time")var done = false//读函数func read(name string, c *sync.Cond) {    //关联锁c.L.Lock()//先让读函数等待通知for !done {fmt.Printf("【%s】 来了,等在门外\n",name)c.Wait()}fmt.Printf("【%s】 入账 ====》\n",name)c.L.Unlock()}//写函数func write(name string, c *sync.Cond) {fmt.Printf("【%s】入帐,作战计划制定中~~~~~ \n",name)time.Sleep(2*time.Second)c.L.Lock()done = truec.L.Unlock()fmt.Printf("======== 作战计划制定完毕 ========\n【%s】 大家进来开会吧! \n",name)c.Broadcast()}func main() {cond := sync.NewCond(&sync.Mutex{})fmt.Println("========= 玄德公 升帐了 =============")for _,name := range []string{"关羽","张飞","赵云"}{go read(name, cond)}go write("孔明", cond)time.Sleep(time.Second * 3)}
  • 输出
========= 玄德公 升帐了 =============【孔明】入帐,作战计划制定中~~~~~ 【关羽】 来了,等在门外【赵云】 来了,等在门外【张飞】 来了,等在门外======== 作战计划制定完毕 ========【孔明】 大家进来开会吧! 【张飞】 入账 ====》【赵云】 入账 ====》【关羽】 入账 ====

3.2 示例(蜀军薪资调整了——单独唤醒)

  • 将上例中 write()最后的广播换成单独唤醒c.Signal():
func write(name string, c *sync.Cond) {fmt.Printf("【%s】入帐,作战计划制定中~~~~~ \n",name)time.Sleep(2*time.Second)c.L.Lock()done = truec.L.Unlock()fmt.Printf("======== 作战计划制定完毕 ========\n【%s】 大家进来开会吧! \n",name)c.Signal()}

结果

随机有个一等待的人入账,之后就没有然后了。因为武将们没有执行唤醒其他人。

========= 玄德公 升帐了 =============【孔明】入帐,作战计划制定中~~~~~ 【张飞】 来了,等在门外【赵云】 来了,等在门外【关羽】 来了,等在门外======== 作战计划制定完毕 ========【孔明】 大家进来开会吧! 【张飞】 入账 ====
  • 再给上例武将们的函数最后添加一个单独唤醒,所有武将将一个一个被换入

为了方便看,在read()中加了一个sleep。
另外,读锁是不互斥的,因此有几个人留在帐内我们并不关心。

func read(name string, c *sync.Cond) {c.L.Lock()for !done {fmt.Printf("【%s】 来了,等在门外\n",name)c.Wait()}fmt.Printf("【%s】 入账 ====》\n",name)time.Sleep(time.Second)c.L.Unlock()c.Signal()}
  • 完整示例

最终修改一下,让刘备单独召见每一个人,大家一个完事喊下一个。

var done = false//读函数func read(name string, c *sync.Cond) {c.L.Lock()for !done {fmt.Printf("【%s】 来了,等在门外\n",name)c.Wait()}fmt.Printf("【%s】 入账 ====》\n",name)time.Sleep(time.Second)c.L.Unlock()fmt.Printf("【%s】出帐喊:下一个进来吧! \n",name)c.Signal()}func write(name string, c *sync.Cond) {fmt.Printf("【%s】入帐,汇报蜀将薪资调整状况 ~~~~~ \n",name)time.Sleep(2*time.Second)c.L.Lock()done = truec.L.Unlock()fmt.Printf("【%s】出帐喊:下一个进来吧! \n",name)c.Signal()}func main() {cond := sync.NewCond(&sync.Mutex{})fmt.Println("========= 玄德公 升帐了 =============")for _,name := range []string{"关羽","张飞","赵云"}{go read(name, cond)}go write("孔明", cond)time.Sleep(time.Second * 10)}

打印结果

========= 玄德公 升帐了 =============【孔明】入帐,汇报蜀将薪资调整状况 ~~~~~ 【关羽】 来了,等在门外【张飞】 来了,等在门外【赵云】 来了,等在门外【孔明】出帐喊:下一个进来吧! 【关羽】 入账 ====》【关羽】出帐喊:下一个进来吧! 【张飞】 入账 ====》【张飞】出帐喊:下一个进来吧! 【赵云】 入账 ====》【赵云】出帐喊:下一个进来吧!

茶叶商城