context context 小 记

Posted Jun 28, 20201 min read

//propagateCancel arranges for child to be canceled when parent is.
func propagateCancel(parent Context, child canceler) {
if parent.Done() == nil {
return //parent is never canceled
}
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 {
//I don't quite understand here:
//1. In the cancel function, all children will be actively canceled. Why do you need this coroutine to cancel?
//2. Why listen to child.Done().
//Answer:
//1. Pay attention to the if else structure here. The condition to get here is that in the process of looking up the parent context upwards, no context of cancleCtx was found. Only cancelCtx has a cancel function. Without the cancel function, you can only monitor Done() in a coroutine way.
//2. Listening to child.Done() is because when the execution of child is ended or canceled, this coroutine can exit, there is no need to wait for the end of parent.
go func() {
select {
case <-parent.Done():
child.cancel(false, parent.Err())
case <-child.Done():
}
}()
}
}