美文网首页
go channel源码分析

go channel源码分析

作者: Jancd | 来源:发表于2018-12-16 04:23 被阅读40次

    go 源码文件:/runtime/chan.go

    type hchan struct {
        qcount   uint           // total data in the queue(队列中数据个数)
        dataqsiz uint           // size of the circular queue(缓冲槽大小)
        buf      unsafe.Pointer // points to an array of dataqsiz elements (指向缓冲槽的指针)
        elemsize uint16
        closed   uint32
        elemtype *_type // element type(数据类型)
        sendx    uint   // send index(发送位置索引)
        recvx    uint   // receive index(接收位置索引)
        recvq    waitq  // list of recv waiters (接收等待列表)
        sendq    waitq  // list of send waiters (发送等待列表)
    
        // lock protects all fields in hchan, as well as several
        // fields in sudogs blocked on this channel.
        //
        // Do not change another G's status while holding this lock
        // (in particular, do not ready a G), as this can deadlock
        // with stack shrinking.
        lock mutex
    }
    

    你可以简单粗暴的把channel的实现理解为 队列 + 锁

    值得注意的是 sendqrecvq字段,它们的类型是 waitq:

    type waitq struct {
        first *sudog
        last  *sudog
    }
    

    这个 waitq 也就是阻塞在channelG(注:这里的G代表着 G-M-P模型中的G)列表。在 csp 模型中 G 可以同时阻塞在不同的 channel 上,于是对 G 进行了封装,引入了 sudog:

    type sudog struct {
        // The following fields are protected by the hchan.lock of the
        // channel this sudog is blocking on. shrinkstack depends on
        // this for sudogs involved in channel ops.
    
        g *g
    
        // isSelect indicates g is participating in a select, so
        // g.selectDone must be CAS'd to win the wake-up race.
        isSelect bool
        next     *sudog
        prev     *sudog
        elem     unsafe.Pointer // data element (may point to stack)
    
        // The following fields are never accessed concurrently.
        // For channels, waitlink is only accessed by g.
        // For semaphores, all fields (including the ones above)
        // are only accessed when holding a semaRoot lock.
    
        acquiretime int64
        releasetime int64
        ticket      uint32
        parent      *sudog // semaRoot binary tree
        waitlink    *sudog // g.waiting list or semaRoot
        waittail    *sudog // semaRoot
        c           *hchan // channel
    }
    

    channel 的创建

    
    func makechan(t *chantype, size int) *hchan {
        elem := t.elem
    
        // compiler checks this but be safe.
        if elem.size >= 1<<16 {    //不大于64k
            throw("makechan: invalid channel element type")
        }
        if hchanSize%maxAlign != 0 || elem.align > maxAlign {
            throw("makechan: bad alignment")
        }
    
        if size < 0 || uintptr(size) > maxSliceCap(elem.size) || uintptr(size)*elem.size > maxAlloc-hchanSize {
            panic(plainError("makechan: size out of range"))
        }
    
        // Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers.
        // buf points into the same allocation, elemtype is persistent.
        // SudoG's are referenced from their owning thread so they can't be collected.
        // TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
        var c *hchan
        switch {  //根据实际情况分配内存。
        case size == 0 || elem.size == 0:
            // Queue or element size is zero.
            c = (*hchan)(mallocgc(hchanSize, nil, true))
            // Race detector uses this location for synchronization.
            c.buf = c.raceaddr()
        case elem.kind&kindNoPointers != 0:
            // Elements do not contain pointers.
            // Allocate hchan and buf in one call.
            c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true))
            c.buf = add(unsafe.Pointer(c), hchanSize)
        default:
            // Elements contain pointers.
            c = new(hchan)
            c.buf = mallocgc(uintptr(size)*elem.size, elem, true)
        }
    
        c.elemsize = uint16(elem.size)
        c.elemtype = elem
        c.dataqsiz = uint(size)
    
        if debugChan {
            print("makechan: chan=", c, "; elemsize=", elem.size, "; elemalg=", elem.alg, "; dataqsiz=", size, "\n")
        }
        return c
    }
    

    未完待续。。

    相关文章

      网友评论

          本文标题:go channel源码分析

          本文链接:https://www.haomeiwen.com/subject/idxtkqtx.html