老卫带你学---go语言中context库里propagateCancel函数

go语言中context库里propagateCancel函数

在这里插入图片描述

// 设置当父context取消时候,子context也取消的逻辑
func propagateCancel(parent Context, child canceler) {
    //父context永远不会被取消(例如WithValue)
	done := parent.Done()
	if done == nil {
		return 
	}
 
	select {
	case <-done:
		// 父context已经被取消(例如父context已经被cancel,而子协程中才使用withcancel(ctx))
		child.cancel(false, parent.Err())
		return
	default:
	}
 
//确定parent最内层的cancel是否是内部实现的cancelCtx
//如果是,则把child放入该cancelCtx的child中
	if p, ok := parentCancelCtx(parent); ok {
		p.mu.Lock()
		if p.err != nil {
			// parent has already been canceled
			child.cancel(false, p.err)
		} else {
			if p.children == nil {
				p.children = make(map[canceler]struct{})
			}
			p.children[child] = struct{}{}
		}
		p.mu.Unlock()
	} else {
//如果不是内部实现的cancelCtx则另外起一个协程
//一直监听父context是否关闭,如果关闭则关闭child
		atomic.AddInt32(&goroutines, +1)
		go func() {
			select {
			case <-parent.Done():
				child.cancel(false, parent.Err())
			case <-child.Done():
			}
		}()
	}
}
 

上面判断parentCancelCtx这个,因为并非所有人实现的context都有children ,当是golang内部实现的cancelCtx时候,可以添加child来让parent取消。而如果是自己实现的parent-context,则一定是让child监听parent-done来观察parent是否结束。

如何判断parent是否是cancelCtx

// &cancelCtxKey is the key that a cancelCtx returns itself for.
var cancelCtxKey int
 
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
	done := parent.Done()
	if done == closedchan || done == nil {
		return nil, false
	}
//cancelCtx 的 value方法会首先检查 key == &cancelCtxKey
//如果是则返回自己
//挺有意思的一个思路
	p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
	if !ok {
		return nil, false
	}
	p.mu.Lock()
	ok = p.done == done
	p.mu.Unlock()
	if !ok {
		return nil, false
	}
	return p, true
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值