目录

  • 概览
  • 例子
  • 源码解读
    • 总结
    • 结构体字段介绍
    • 函数介绍
      • Add函数
      • Wait函数
      • Done

概览

使用场景:管理多个goroutine,用于等待多个goroutine都完成后,主goroutine继续运行

例子

wg  := new(sync.WaitGroup)
wg.Add(n) //n为要等待的goroutine个数
go func() {wg.Done() //对应wg.Add(-1)
}
...
wg.Wait()

源码解读

总结

通过state1一个数组来表示当前的delta,waiter、semap信号量大小,如果调用Add,会delta会加上输入的大小,然后返回,如果多个Wait调用,每个Wait都会阻塞,每个进入waiter都会加1,因为semap信号量为0,所以每个waiter都会阻塞,直到delta为0(关键点,Add加负数的时候,如果delta不为0,直接返回,为0,则循环释放信号量),add会循环waiter,每回减1,释放信号量,每回减1,直到为0,每释放一个信号量,一个Wait返回,直到信号量为0,每个Wait都返回了。

结构体字段介绍

type WaitGroup struct {noCopy noCopy// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.// 64-bit atomic operations require 64-bit alignment, but 32-bit// compilers do not ensure it. So we allocate 12 bytes and then use// the aligned 8 bytes in them as state, and the other 4 as storage// for the sema.state1 [3]uint32
}
  1. noCopy 标记位,用作go vet检查,如果当前Struct被copy了,则会报错
    实例代码:
 wg := sync.WaitGroup{}wg.Add(1)copyOne := wgcopyOne.Add(1)go func() {fmt.Println("add -1")wg.Done()}()wg.Wait()
}

上面代码可以正常运行
goland会提示如下错误

运行go vet会报下面错误

2. state1存储信号量、waiter、delta
state1[0]:semap,信号量
state1[1]:waiter个数
state1[2]:delta

函数介绍

Add函数

func (wg *WaitGroup) Add(delta int) {statep, semap := wg.state() //对state1进行拆分,获取statep和semap,statep对应state1[1]state1[2],semap的对应statep[0]state := atomic.AddUint64(statep, uint64(delta)<<32) //stetep[1]即state1[2]存储deltav := int32(state >> 32) //v为state[1],当前delta大小w := uint32(state) // w为state[0],当前waiter个数if v < 0 {panic("sync: negative WaitGroup counter")}if w != 0 && delta > 0 && v == int32(delta) {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}if v > 0 || w == 0 { //关键点,当前还未调用Wait()或者当前的delta总数还是大于0return}if *statep != state {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}// Reset waiters count to 0.// 当前v即delta为0时,则一个个通知waiter,通过进行release信号量,实际即semap+1*statep = 0for ; w != 0; w-- { //如果有多个waiter,semap为waiter个数runtime_Semrelease(semap, false, 0)}
}

Wait函数

func (wg *WaitGroup) Wait() {statep, semap := wg.state() //同Add方法第一行,获取statep和semapfor {state := atomic.LoadUint64(statep) v := int32(state >> 32) // 当前delta大小w := uint32(state) //当前waiter个数if v == 0 { // 如果当前delta大小为0,则直接返回,没有Add过,或者已经被Done掉了return}// Increment waiters count. 如果当前state没有被修改过,则statep加1,实际是w+1了,即多了一个waiterif atomic.CompareAndSwapUint64(statep, state, state+1) {runtime_Semacquire(semap) //这是acquire一个实际为semap减1,因为semap当前还是0,这时会被阻塞if *statep != 0 {panic("sync: WaitGroup is reused before previous Wait has returned")}if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer(wg))}return}}
}

Done

实际为Add -1

func (wg *WaitGroup) Done() {wg.Add(-1)
}

golang源代码阅读,sync系列-WaitGroup相关推荐

  1. golang源代码阅读--Negroni

    Let's Go 简介 Negroni 是一个框架吗? 路由? 基本功能 源码阅读 Negroni Handler处理器 如何构建中间件处理链 中间件如何被调用 参考资料 简介 在 Go 语言里,Ne ...

  2. golang中的sync.WaitGroup

    golang中的sync.WaitGroup Posted on 2015/04/09刚才看golang的sync的包,看见一个很有用的功能.就是WaitGroup. 先说说WaitGroup的用途: ...

  3. Golang gorouting 并发控制 sync.WaitGroup 介绍与使用

    WaitGroup简称同步组,用于等待goroutines结束的. 官方文档: type WaitGroupA WaitGroup waits for a collection of goroutin ...

  4. Tomcat源代码阅读系列之八:Tomcat 设计模式总结

    本篇我们将来分析一下Tomcat中所涉及到设计模式,本文我们将主要来分析 外观模式 , 观察者模式 , 责任链模式 , 模板方法模式 , 命令模式 . 在开始本文之前,笔者先说明一下对于设计模式的一点 ...

  5. 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)

    本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...

  6. golang中并发sync和channel

    golang中并发sync和channel chenbaoke · 2014-12-08 13:00:01 · 19151 次点击 · 预计阅读时间 5 分钟 · 不到1分钟之前 开始浏览 这是一个创 ...

  7. GoLang之map底层系列二(浅显学习)

    文章目录 GoLang之map底层系列二(浅显学习) 1.map++ 2.map引用传递 3.map不是并发安全 4.map的value为空接口 5.map的value为切片 6.value,ok=m ...

  8. json阅读器_Flutter小说阅读器系列一:使用Bloc模式获取起点小说关键字提示

    Bloc模式下的小说关键字提示效果图 最近难得有些闲暇时间,所以我又打算做一个小说阅读器,以前倒是用RN+Golang写了一个,不过当时太过放飞自我导致自己看起来都很费力,这次我准备换成Flutter ...

  9. GoLang之使用sync.Cond

    文章目录 GoLang之使用sync.Cond 1.Cond结构体 1.1.Cond结构体 1.2Broadcast方法 1.3Signal方法 1.4Wait方法 2.NewCond函数 3.介绍 ...

  10. XV6源代码阅读-文件系统

    Exercise1 源代码阅读 文件系统部分 buf.h fcntl.h stat.h fs.h file.h ide.c bio.c log.c fs.c file.c sysfile.c exec ...

最新文章

  1. 深入浅出Dotnet Core的项目结构变化
  2. .NET使用NPOI读取Word模板并替换关键字并下载
  3. Echarts地图编写
  4. 【计算机网络】Quiz集合
  5. python取字符串一部分_python,如何获取字符串中的子字符串,部分字符串
  6. Redis info信息(转载)
  7. wps怎么下载仿宋gb2312_仿宋gb2312字体官方下载
  8. Ubuntu系统下载工具的推荐
  9. QQ魔法卡片辅助工具外挂silverlight版
  10. 从零開始搭建微信硬件开发环境全过程——1小时掌握微信硬件开发流程
  11. 魔兽世界服务器名称修改,魔兽世界怀旧服服务器名称
  12. 2018 大数据面试
  13. 【WebView】关于Android WebView 的一些坑
  14. 宝贝怎么查询历史价格?有何意义?
  15. 王者荣耀段位计算器软件
  16. 计算机考研零基础英语怎么复习,考研英语复习办法千万种,总有一种适合你!...
  17. 商务搜索引擎_外贸研修 | 世界各国常用搜索引擎,开发客户必备!
  18. 布隆过滤器(BloomFilter)
  19. SQLite简介,C#调用SQLite
  20. 计算机地图制图成图方法,第五章 地图成图方法.ppt

热门文章

  1. 《辛雷学习方法》读书笔记——第三章 身体
  2. python查询46级成绩
  3. 使用WP-Salts-Update-CLI自动更新您的WordPress盐
  4. 医学数据窗宽窗位调节
  5. C# .net+DevExpress自定义控件(UserControl)之分页控件
  6. 模块Datetime
  7. 9527风先生的文章《Ubuntu20.04配置ORBSLAM2并运行》 :验证是能走通的
  8. android实现推箱子代码,android开发--推箱子小游戏(二)
  9. php nofollow,php如何实现统一给外部链接添加nofollow值?
  10. 毁灭战士 DOOM 3DO 源代码公开