go: WaitGroup 原理: 直到最底层

  • 参考
    • [好文](https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-sync-primitives/)
  • 经典用法
    https://gobyexample.com/waitgroups
    • 构造wg
    • wg.Add(1)
    • defer wg.Done(),也就是wg.Add(-1)
    • 并行搞起
    • wg.wait()
  • WaitGroup重要变量:counter,waiter,sema(信号量)
    • 推论:counter==0认为是并发任务执行完毕。
      • 为什么?整个流程上来就是Add把counter+1,正常流程会把Add全部执行完再wait。任何情况下,只要wait发现count==0,那就是并行任务执行完了。
  • Add(delta)
    • CAS counter + delta
    • counter > 0 或者 waiter == 0 return(为啥这么写?return是为了不执行后面的sema操作(通知等待的goroutine)。counter>0或者waiter==0不执行是为啥?waiter==0都没人在等,当然不需要执行后面的通知goroutine,counter>0说明还没干完活呢没把counter减到0呢,也没必要去执行后面的通知)
      • 其实可以看后面的注释:当前的goroutine,当waiters>0的时候把counter设置成了0。(counter==0任务执行完了且有人在等待咱们唤醒,那就要唤醒)(没有return的情况下,说明v==0 && w !=0)。说明了啥呢?现在不可能有并发改state了。为啥?
        • Adds不能跟Wait并发发生(看经典用法,按常理,肯定是一个一个add完最后才wait的)
        • Wait不会增加waiter如果它看到counter==0
    • 重置waiter数量为0
    • 对sema执行waiter次 runtime_SemRelease
  • Wait()
    • 死循环
      • 获取一遍counter和waiter
      • counter == 0,return。(counter归零了==执行完了,可以直接返回,否则说明还没执行完,需要睡一会等人来叫醒我)
      • if CAS waiter+1 成功
        • 对sema执行1次runtime_Semacquire(睡吧等人叫醒我)
        • 返回
  • 这过程中又涉及俩底层玩意儿
    • runtime_SemRelease(叫醒人)
      原子+1,然后通知等待的goroutine(如果一个goroutine在获取过程中阻塞了)
    • runtime_Semacquire(睡吧等人叫醒我)
      ​阻塞等待直到信号量>0然后原子-1
  • 所以把整个官方例子串起来那就是(假设add两遍)
    • wg.Add(1)
      • counter=1,waiter=0,返回,sema没改=0
    • go funcA() {并行干点A事情; }
    • wg.Add(1)
      • counter=2,waiter=0,返回,sema没改=0
    • go funcB() {并行干点B事情; }
    • wg.wait()
      • CAS waiter + 1 = 1
      • runtime_Semacquire,阻塞等待。
    • A干完了wg.Add(-1)
      • counter-1=1,counter>0 return
    • B干完了wg.Add(-1)
      • counter-1=0,waiter=1,没有直接返回
      • 重置waiter=0
      • 执行1次runtime_SemRelease。
        • 原子sema+1=1,通知等待的goroutine(在wait的那哥们)
    • wg.wait()收到通知,信号量>0了,原子sema-1=0
  • 更底层怎么实现的?/usr/local/go/src/runtime/sema.go
    • runtime_SemRelease(叫醒人)
      原子+1,然后通知等待的goroutine(如果一个goroutine在获取过程中阻塞了)
    • runtime_Semacquire(睡吧等人叫醒我)【其实这是很多锁的统一套路。比如Java。没啥可说的,这就是沉淀下来的经验,不好深究每一行是为什么】https://blog.csdn.net/waltonhuang/article/details/110797972
      ​阻塞等待直到信号量>0然后原子-1
      • easycase:直接看一下sema,如果==0,获取失败,否则,原子-1成功则获取成功。
      • hardercase:
        • 死循环:
          • 增加waiter数量
          • 再试一下获取,成功就返回
          • 排队
          • 休眠
  •  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值