WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
} // 包了一层,把 parent 赋值给子 context
func newCancelCtx(parent Context) cancelCtx {
return cancelCtx{Context: parent}
} type cancelCtx struct {
Context mu sync.Mutex // protects following fields
done chan struct{} // created lazily, closed by first cancel call
children map[canceler]struct{} // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
}
func propagateCancel(parent Context, child canceler) {
if parent.Done() == nil {
return // parent is never canceled
}
// 判断 parent 是否为 cancelCtx,timerCtx 也属于 cancelCtx,cancelCtx 有 child
if p, ok := parentCancelCtx(parent); ok {
p.mu.Lock()
if p.err != nil {
// cancelCtx 被 cancel() 的时候,会给err属性赋值
// parent has already been canceled
child.cancel(false, p.err)
} else { // parent 没有被 cancel()
if p.children == nil {
p.children = make(map[canceler]struct{})
}
p.children[child] = struct{}{} // 将 child 添加到 parent 中
}
p.mu.Unlock()
} else { // parent 的状态未确定
go func() {
select {
case <-parent.Done(): // 如果可以从 parent 中获取到值,说明 parent 被 cancel 了
child.cancel(false, parent.Err())
case <-child.Done():
}
}()
}
} // 类型判断
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
for {
switch c := parent.(type) {
case *cancelCtx:
return c, true
case *timerCtx:
return &c.cancelCtx, true
case *valueCtx:
parent = c.Context
default:
return nil, false
}
}
}

分析下 WithCancel 返回的函数

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
} func (c *cancelCtx) cancel(removeFromParent bool, err error) {
// 被 cancel 的 cancelCtx 的 err 属性,必须被赋值
if err == nil {
panic("context: internal error: missing cancel error")
}
c.mu.Lock()
if c.err != nil {
c.mu.Unlock()
return // 已经被 cancel
}
c.err = err
if c.done == nil {
c.done = closedchan // 注意此处!!!
} else {
close(c.done) // close 后,select 可以不断获取到默认值
}
// close 掉所有 child
for child := range c.children {
// NOTE: acquiring the child's lock while holding parent's lock.
child.cancel(false, err)
}
c.children = nil
c.mu.Unlock() if removeFromParent {
removeChild(c.Context, c)
}
} func removeChild(parent Context, child canceler) {
// 只有 cancelCtx 类型的 context,才有 child
p, ok := parentCancelCtx(parent)
if !ok {
return
}
p.mu.Lock()
if p.children != nil {
delete(p.children, child)
}
p.mu.Unlock()
} // closedchan is a reusable closed channel.
// closedchan init() 的时候就被 close 了,所以是可以通过 select 不断获取值的
var closedchan = make(chan struct{})
func init() {
close(closedchan)
}

go context 源码分析的更多相关文章

  1. Context源码分析

    我们做安卓开发,时时都在和Context打交道,那么Context到底是什么?有什么作用?如何与Application,Activity,Service等实例发生联系的?等等 Context是什么? ...

  2. Android源码分析-全面理解Context

    前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...

  3. requirejs源码分析: requirejs 方法–2. context.require(deps, callback, errback);

    上一篇 requirejs源码分析: requirejs 方法–1. 主入口  中的return context.require(deps, callback, errback);  调用的是make ...

  4. ABP源码分析二十四:Notification

    NotificationDefinition: 用于封装Notification Definnition 的信息.注意和Notification 的区别,如果把Notification看成是具体的消息 ...

  5. asp.net mvc 之旅 —— 第六站 ActionFilter的应用及源码分析

    这篇文章我们开始看一下ActionFilter,从名字上其实就大概知道ActionFilter就是Action上的Filter,对吧,那么Action上的Filter大概有几个呢??? 这个问题其实还 ...

  6. 深入理解 spring 容器,源码分析加载过程

    Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC ...

  7. jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

    Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...

  8. jQuery 2.0.3 源码分析 Deferred概念

    JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...

  9. jQuery-1.9.1源码分析系列(一)整体架构续

    这一节主要是jQuery中最基础的几个东东 2.    jQuery的几个基础属性和函数 a. jQuery.noConflict函数详解 在jQuery初始化的时候保存了外部的$和jQuery _j ...

随机推荐

  1. [设计原则与模式] 面向对象程序设计之五大原则(SOLID)

    cp from:  https://blog.csdn.net/zhangbuzhangbu/article/details/51719952 S.O.L.I.D是面向对象设计和编程(OOD& ...

  2. 多个请求共用一个Servlet(JavaWEB)

    我们在对JavaWEB工程进行开发的时候,我们经常会遇到这样一个问题,在jsp中发送到Servlet的每一个请求都要写一个对应的Servlet,这样会造成一个工程完成下来需要写几十个Servlet,那 ...

  3. pdf 中内容的坐标系

    PDF Page Coordinates (page size, field placement, etc.) AcroForm, Basics, Automation Page coordinate ...

  4. Java基础 Scanner 使用nextInt接收整数

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  5. [原]error LNK2005:"XXX已经在 XXX.obj 中定义 使用 /FORCE(强制文件输出)暴力解决

    参考:https://blog.csdn.net/LG1259156776/article/details/80828720 https://blog.csdn.net/cai18381306175/ ...

  6. Dart对象和类

    /* 面向对象编程(OOP)的三个基本特征是:封装.继承.多态 封装:封装是对象和类概念的主要特性.封装,把客观事物封装成抽象的类,并且把自己的部分属性和方法提供给其他对象调用, 而一部分属性和方法则 ...

  7. ifc osg施工现场模拟

    基于ifc数据模型的施工现场模拟

  8. mobile crane 1

    void MobileCrane::rotateRope2() { //double r_angle1 = rotateRope + rorate3; //std::cout << &qu ...

  9. python for 无限循环

    class Infinit: def __iter__(self): return self def __next__(self): return None for i in Infinit(): p ...

  10. Spring cloud微服务安全实战-3-12session固定攻击防护

    getSession这个方法里面的逻辑,会根据传过来的cookie里面带的JSessionID在你的服务器上去找一个session,如果能找到,就用这个已经存在的session,这个getSessio ...