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()
}
posted @   朝阳1  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示