GO中的sync.Cond
条件变量是基于互斥锁的,它必须基于互斥锁才能发挥作用,条件变量的初始化离不开互斥锁,并且它的方法有点也是基于互斥锁的
// 使当前goroutine进入阻塞状态,等待其他goroutine唤醒
func (c *Cond) Wait() {}
// 唤醒一个等待该条件变量的goroutine,如果没有goroutine在等待,则该方法会立即返回
func (c *Cond) Signal() {}
// 唤醒所有等待该条件变量的goroutine,如果没有goroutine在等待,则该方法会立即返回。
func (c *Cond) Broadcast() {}
入门
package main
import (
"log"
"sync"
"time"
)
func read(index int, c *sync.Cond) {
c.L.Lock()
c.Wait()
log.Println(index, "开始读")
c.L.Unlock()
}
func write(c *sync.Cond) {
log.Println("开始写")
time.Sleep(time.Second)
log.Println("唤醒其中一个或者n个goroutine")
//c.Signal()
c.Broadcast()
}
func main() {
cond := sync.NewCond(&sync.Mutex{})
for i := 1; i <= 5; i++ {
go func(index int) {
read(index, cond)
}(i)
}
write(cond)
time.Sleep(time.Second * 3)
}
生产者消费者
package main
import (
"log"
"sync"
"time"
)
func main() {
// mailbox 代表信箱
// 0 代表信箱是空的,1代表信箱是满的
var mailbox uint8
// lock 代表信箱上的锁
var lock sync.RWMutex
// sendCond 代表专用于发信的条件变量
var sendCond = sync.NewCond(&lock)
// reveCond 代表专用于收信的条件变量
var reveCond = sync.NewCond(lock.RLocker())
// sign 用于传递演示完成的信号
sign := make(chan struct{}, 2)
max := 5
go func(max int) { // 用于发信
defer func() {
sign <- struct{}{}
}()
for i := 1; i <= max; i++ {
time.Sleep(time.Millisecond * 5)
lock.Lock()
for mailbox == 1 {
sendCond.Wait()
}
log.Printf("sender [%d]: the mailbox is empty.", i)
mailbox = 1
log.Printf("sender [%d]: the letter has been sent.", i)
lock.Unlock()
reveCond.Signal() // 唤醒一个正在等待的goruntine
}
}(max)
go func(max int) { // 用于收信
defer func() {
sign <- struct{}{}
}()
for j := 1; j <= max; j++ {
time.Sleep(time.Millisecond * 500)
lock.RLock()
for mailbox == 0 {
reveCond.Wait()
}
log.Printf("receiver [%d]: the mailbox is full.", j)
mailbox = 0
log.Printf("receiver [%d]: the letter has been received.", j)
lock.RUnlock()
sendCond.Signal() // 唤醒一个正在等待的goruntine
}
}(max)
<-sign
<-sign
}
连接池示例
package main
import (
"container/list"
"fmt"
"math/rand"
"sync"
"time"
)
// 连接池
type Pool struct {
lock sync.Mutex // 锁
clients list.List // 连接
cond *sync.Cond // cond实例
close bool // 是否关闭
}
// Redis Client
type Client struct {
id int32
}
// 创建Redis Client
func NewClient() *Client {
return &Client{
id: rand.Int31n(100000),
}
}
// 关闭Redis Client
func (this *Client) Close() {
fmt.Printf("Client:%d 正在关闭", this.id)
}
// 创建连接池
func NewPool(maxConnNum int) *Pool {
pool := new(Pool)
pool.cond = sync.NewCond(&pool.lock)
// 创建连接
for i := 0; i < maxConnNum; i++ {
client := NewClient()
pool.clients.PushBack(client)
}
return pool
}
// 从池子中获取连接
func (this *Pool) Pull() *Client {
this.lock.Lock()
defer this.lock.Unlock()
// 已关闭
if this.close {
fmt.Println("Pool is closed")
return nil
}
// 如果连接池没有连接 需要阻塞
for this.clients.Len() <= 0 {
this.cond.Wait()
}
// 从链表中取出头节点,删除并返回
ele := this.clients.Remove(this.clients.Front())
return ele.(*Client)
}
// 将连接放回池子
func (this *Pool) Push(client *Client) {
this.lock.Lock()
defer this.lock.Unlock()
if this.close {
fmt.Println("Pool is closed")
return
}
// 向链表尾部插入一个连接
this.clients.PushBack(client)
// 唤醒一个正在等待的goruntine
this.cond.Signal()
}
// 关闭池子
func (this *Pool) Close() {
this.lock.Lock()
defer this.lock.Unlock()
// 关闭连接
for e := this.clients.Front(); e != nil; e = e.Next() {
client := e.Value.(*Client)
client.Close()
}
// 重置数据
this.close = true
this.clients.Init()
}
func main() {
var wg sync.WaitGroup
pool := NewPool(3)
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
// 获取一个连接
client := pool.Pull()
fmt.Printf("Time:%s | 【goruntine#%d】获取到client[%d]\n", time.Now().Format("15:04:05"), index, client.id)
time.Sleep(time.Second * 5)
fmt.Printf("Time:%s | 【goruntine#%d】使用完毕,将client[%d]放回池子\n", time.Now().Format("15:04:05"), index, client.id)
// 将连接放回池子
pool.Push(client)
}(i)
}
wg.Wait()
}
分类:
Go
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!