Go 标准库源码分析 - sync包的cond

2023-12-31 11:48
文章标签 分析 源码 go 标准 cond sync

本文主要是介绍Go 标准库源码分析 - sync包的cond,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

sync包的cond实现了一种条件变量,当共享的资源未准备好时,多个goroutine挂起等待,直到一个master goroutine通知事件发生。

一、数据结构

type Cond struct {noCopy noCopy              // 实现了Locker接口,使得Cond对象在go vet扫描时能够检测出Cond对象是否被复制L Locker                   // 实现了Locker接口,通常使用Mutex或RWMutexnotify  notifyList         // 维护了等待被唤醒的goroutine队列checker copyChecker        // 实际上是uintptr对象,保存自身对象地址
}

 二、使用方法

1. NewCond

构建一个新的Cond对象,需要传入一个Locker

func NewCond(l Locker) *Cond {return &Cond{L: l}
}

2. Wait

在调用该方法时,需保证已获得了Cond对象的锁,否则会报错

func (c *Cond) Wait() {c.checker.check()                        // 检查Cond对象是否被复制t := runtime_notifyListAdd(&c.notify)    // 将当前goroutine加入等待唤醒队列c.L.Unlock()runtime_notifyListWait(&c.notify, t)     // 将当前goroutine挂起,接收到通知时才会被唤醒c.L.Lock()
}

3. Signal

会按顺序唤醒一个等待的goroutine

func (c *Cond) Signal() {c.checker.check()runtime_notifyListNotifyOne(&c.notify)
}

4. Broadcast

会唤醒所有等待的goroutine

func (c *Cond) Broadcast() {c.checker.check()runtime_notifyListNotifyAll(&c.notify)
}

可以看到在Wait、Signal、Broadcast方法中均有调用到私有属性checker的check方法去检查cond对象是否被复制,以下是check方法的代码

func (c *copyChecker) check() {if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&!atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&uintptr(*c) != uintptr(unsafe.Pointer(c)) {panic("sync.Cond is copied")}
}
  1. 首先检查当前checker的地址是否等于保存在checker中的地址,因为Cond对象被复制时,checker会被重新分配内存,此时与保存在checker的地址不等
  2.  check方法第一次调用时会将checker对象地址赋值给自身,第二步对checker对象进行原子CAS操作,将当前checker地址赋值给值为空的checker
  3. 存在一种情况,在CAS操作前,该goroutine被挂起,其他goroutine并发地修改了checker而导致此次CAS操作返回false而panic,因此需要重复操作1
  4. 若1、2、3皆不满足,则表示该Cond是复制的,抛出panic

 

这篇关于Go 标准库源码分析 - sync包的cond的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/555945

相关文章

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

go 指针接收者和值接收者的区别小结

《go指针接收者和值接收者的区别小结》在Go语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

Go 语言中的select语句详解及工作原理

《Go语言中的select语句详解及工作原理》在Go语言中,select语句是用于处理多个通道(channel)操作的一种控制结构,它类似于switch语句,本文给大家介绍Go语言中的select语... 目录Go 语言中的 select 是做什么的基本功能语法工作原理示例示例 1:监听多个通道示例 2:带

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++