content.Context 接口
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
1、WithCancel: 根据父parent Context构建一个子context
// 根据父parent context构建子context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
if parent == nil {
panic("cannot create context from nil parent")
}
c := newCancelCtx(parent) // 构建子context结构
propagateCancel(parent, &c) // 构建父子context的关系
return &c, func() { c.cancel(true, Canceled) }
}
// propagateCancel arranges for child to be canceled when parent is.
// 父context在cancel的时候,通知子context进行cancel
func propagateCancel(parent Context, child canceler) {
done := parent.Done() // 判断父context是否可以cancel
if done == nil {
return // parent is never canceled
}
select {
case <-done:
// parent is already canceled
// 如果parent context已经canceld, 则cancel child context
child.cancel(false, parent.Err())
return
default:
}
// 下面会详细阐述
// 如果parent context 是否是cancelCtx
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{}{}
// 将child context绑定到parent context 的children map中
}
p.mu.Unlock()
} else {
// 如果parent context 不是cancelCtx类型,则启动新的goroutine进行监控
atomic.AddInt32(&goroutines, +1)
go func() {
select {
case <-parent.Done():
child.cancel(false, parent.Err())
case <-child.Done():
}
}()
}
}
// cancel closes c.done, cancels each of c's children, and, if
// removeFromParent is true, removes c from its parent's children.
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
// 非对外接口,内部调用确保了err的传值
if err == nil {
panic("context: internal error: missing cancel error")
}
c.mu.Lock()
if c.err != nil {
// 如果c.err != nil, 代表着对应的context已经被canceled
c.mu.Unlock()
return // already canceled
}
c.err = err
// 懒加载,确保c.done的赋值,closedchan是包内可重复使用的已经关闭的chan
if c.done == nil {
c.done = closedchan
} else {
close(c.done)
}
// cancel对应的children context
for child := range c.children {
// NOTE: acquiring the child's lock while holding parent's lock.
child.cancel(false, err)
}
// 将对应的children赋空
c.children = nil
c.mu.Unlock()
if removeFromParent {
removeChild(c.Context, c)
}
}
重点:parentCancelCtx
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
// 如果done为nil,说明parent context不支持 cancel,那么就不可能是 cancelCtx
// 如果done为可复用的closedchan,说明 parent context 已经被canceled
done := parent.Done()
if done == closedchan || done == nil {
return nil, false
}
// 如果parent不是context 原生的 cancelCtx,则返回false
p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
if !ok {
return nil, false
}
p.mu.Lock()
ok = p.done == done
// p.done == done,表明当前parent实现了cancelCtx类型
// p.done != done,表明当前parent未实现cancelCtx类型,有可能是parent.parent context的类型是cancelCtx,因此不能保证parent context可以控制child context, 只能单独监听parent.Done()
p.mu.Unlock()
if !ok {
return nil, false
}
return p, true
}
其他的WithValue(), WithDeadline(), WithTimeOut()就不做阐述,类似上面的流程