@
1. sync.Cond结构体
| type Cond struct { |
| noCopy noCopy |
| L Locker |
| notify notifyList |
| checker copyChecker |
| } |
- 作用
实现了一个条件变量,用于等待一个或一组协程满足条件后唤醒这些协程。
从结构体定义可知,每个Cond关联一个Locker(*Mutex或*RWMutex)。
2. sync.Cond结构体常用方法
| 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) |
| } |
打印结果
| ========= 玄德公 升帐了 ============= |
| 【孔明】入帐,汇报蜀将薪资调整状况 ~~~~~ |
| 【关羽】 来了,等在门外 |
| 【张飞】 来了,等在门外 |
| 【赵云】 来了,等在门外 |
| 【孔明】出帐喊:下一个进来吧! |
| 【关羽】 入账 ====》 |
| 【关羽】出帐喊:下一个进来吧! |
| 【张飞】 入账 ====》 |
| 【张飞】出帐喊:下一个进来吧! |
| 【赵云】 入账 ====》 |
| 【赵云】出帐喊:下一个进来吧! |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了