golang-> context源码阅读与分析


context源码阅读与分析">

golang使用context作为goroutine之间的控制器,举例:

<code>package main import ( "context" "log" "time" ) func UseContext(ctx context.Context) { for { select { case /<code>

首先看下context是个什么东东

context包里面是一个interface接口,实现了下面4个方法

<code>type Context interface { Deadline() (deadline time.Time, ok bool) // Deadline() 返回上下文完成工作的时间 Done() /<code>

既然是接口,就找一个具体实现

<code>// background返回的是一个实现了 Context接口全部方法 的空方法的context func Background() Context { return background } // but what is background? it's: var ( background = new(emptyCtx) todo = new(emptyCtx) ) type emptyCtx int // 下面是实现context接口的4个方法 func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return } func (*emptyCtx) Done() /<code>

Background()既然是一个实现了ctx接口全部方法的空实例,那么context.WithCancel()是一个什么东东

<code>// 主实现逻辑,传入一个context,返回一个context和一个CancelFunc(取消函数) func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) // 初始化一个取消函数 propagateCancel(parent, &c) return &c, func() { c.cancel(true, Canceled) } } // 初始化一个cancelCtx,context等于传进来的 func newCancelCtx(parent Context) cancelCtx { return cancelCtx{Context: parent} } type cancelCtx struct { Context mu sync.Mutex // 空值 done chan struct{} // 空值 children map[canceler]struct{} // 空值 err error // 空值 }/<code>

上面可以看出done其实是一个空结构体的chan,接下来看是如何把信号传递给done这个chan的,下面看下cancel()(取消函数)

<code>// 取消关闭 c.done,消去c的每个子结点, // 如果 removeFromParent为真,从父类的子类中移除c。 func (c *cancelCtx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.err != nil { c.mu.Unlock() return // already canceled } c.err = err if c.done == nil { c.done = closedchan } else { close(c.done) // 调用c.done } 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) } }/<code>

这里调用cancel的时候就是调用了 close(c.done)