golang-> context源碼閱讀與分析


golang-> 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)


分享到:


相關文章: