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

@

1. sync.Cond结构体

  • 结构体定义
type Cond struct {
noCopy noCopy
L Locker
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 main
import (
"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 = true
c.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 = true
c.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 = true
c.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)
}

打印结果

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

posted on   运维开发玄德公  阅读(34)  评论(0编辑  收藏  举报  

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示