首页 > 其他分享 >GO中的sync.Cond

GO中的sync.Cond

时间:2024-04-23 16:15:42浏览次数:17  
标签:lock goroutine sync Client Cond func GO

条件变量是基于互斥锁的,它必须基于互斥锁才能发挥作用,条件变量的初始化离不开互斥锁,并且它的方法有点也是基于互斥锁的

// 使当前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 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()
}

标签:lock,goroutine,sync,Client,Cond,func,GO
From: https://www.cnblogs.com/qcy-blog/p/18153060

相关文章

  • 分类算法(Classification Algorithm)需求记录
    [toc]比如说,在WEB扫描器场景中。一个扫描器在扫描过程中,它可以自动识别接口类型并采用相应分类规则进行漏洞检测的算法,这种通常属于一种称为"智能扫描"(IntelligentScanning)或"漏洞扫描引擎"的技术。这些算法利用机器学习、深度学习和模式识别等技术,通过分析网络流量、响应内容......
  • MySQL的在sync_binlog!=1造成1236报错【转】
    前言本文总结了主从复制的原理及日常运维的坑1.主从复制简介MySQL复制是指从一个MySQL主服务器(master)将数据拷贝到另一台或多台MySQL从服务器(slaves)的过程,将主数据库的DDL和DML操作通过二进制日志传到从库服务器上,然后在从服务器上对这些日志重新执行,从而使得主......
  • django种列表输出样式问题,带[]和不带的方法
    比如入库的时候,同一个用户名,多个订单,入库的时候users_list=list(unique_users)OrderList.objects.create(order_des=f"项目名称:{title},账号:{','.join(users_list)},共计新开{selected_ips_count}个",)比如账号不同显示入库的格式和同一个账号入库的格式不一样项目名称:xxx,......
  • Django使用MSSQL创建数据表
    Django使用MSSQL创建数据表Django使用MSSQL创建数据表Django是一个基于Python的开源Web应用框架,它提供了一套完整的开发工具和库,用于快速构建高效、安全的Web应用程序。MSSQL是一种关系型数据库管理系统,由Microsoft开发和维护。在Django中使用MSSQL创建数据表,需要进行以下步骤:......
  • Django常用命令
    安装django:pipinstalldjango安装依赖pipinstall-rrequirements.txt创建项目:django-adminstartprojectproject_name创建应用django-adminstartappapp_name运行端口:pythonmanage.pyrunserverpythonmanage.pyrunserver8080创建数据库命令python3.9manage.......
  • linux 中安装conda
     001、下载镜像源a、地址清华镜像源:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/b、下载最新版本,注意两点:1、最新的,可以参考后边的发布日期;2、选择linux版本,架构选x86_64的  002、确认一下系统[root@PC1software]#cat/etc/redhat-releaseCentOSLi......
  • 无root权限,解决conda环境的报错ImportError: /lib/x86_64-linux-gnu/libstdc++.so.6:
    网上的方法都需要sudo或者root权限,但是服务器多是实验室公用,没有ruuto权限,因此更好的办法是通过conda只改自己虚拟环境的环境变量。问题原因问题的根本原因是Linux系统没有GLIBCXX_3.4.30动态链接库。这个库和gcc版本有关。因此要么你更换版本,要么找一个别的so链接到这个连接......
  • gojs2.1去水印
    go.jsgo-debug.jsgo-module.jsES6模块go-debug-module.js这四个文件,具体看你使用哪一个搜索String.fromCharCode找到下图位置,这是我的格式化之后的样子 然后在 returnf 之前添加代码if(f.indexOf('GoJS2.1evaluation')>-1||f.indexOf('(c)1998-......
  • goweb性能分析 - 远程分析
    gin集成pporfmain.go添加import _"net/http/pprof"gin路由添加//ris*gin.Enginepprof.Register(r)本地电脑链接到远程web服务进行分析然后本地电脑打开假设你的goweb程序服务地址是192.168.2.25:3100gotoolpprof-http=:8080http://192.168.2.25:3100/debug......
  • mipi dsi4线720P国产gowin lattice crosslink配套屏Fpga dsi
     1.产品概述    显示屏LCDMIPIDSI4lane,支持分辨率720*1280,60HZ彩色显示。用于对接国产GOWIN的NR-9C的开发板和LATTICE的CROSSLINK开发板,显示MIPIDSI 功能。      MIPIDSI是4-LANE,MIPI速率在480MHZ。支持LP模式初始化和HS模式显示数据发送。    ......