目录
1.channel底层数据结构是什么
channel底层的数据结构是hchan,包括一个循环链表和2个双向链表
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
}
buf:循环链表
sendx:循环链表中已发送的位置
recvx: 循环链表中已接受的位置
qcount:环形队列的实际大小
dataqsiz:环形队列的容量
elemsize:环列队列中元素的大小
elemtype:环形队列中元素的类型
closed:环形队列是否关闭
recvq:等待接收groutinue链表
sendq:等待发送send groutinue链表
lock:悲观锁
结构图如下所示

2.channel创建的底层实现
创建channel底层调用的是makechan,为新创建的channel分配内存空间,分为下面的三种情况:
- 不带缓冲区:只需要给hchan分配内存空间。
- 带缓冲区且不包括指针类型:同时给hchan和环形队列缓存buf分配一段连续的内存空间。
- 带缓冲区且包括指针类型:分别给hchan和环形队列缓存buf分配不同的内存空间。
源码如下:
func makechan64(t *chantype, size int64) *hchan {
if int64(int(size)) != size {
panic(plainError("makechan: size out of range"))
}
return makechan(t, int(size))
}
func makechan(t *chantype, size int) *hchan {
elem := t.elem
// compiler checks this but be safe.
if elem.size >= 1<<16 {
throw("makechan: invalid channel element type")
}
if hchanSize%maxAlign != 0 || elem.align > maxAlign {
throw("makechan: bad alignment")
}
mem, overflow := math.MulUintptr(elem.size, uintptr(size))
if overflow || mem > maxAlloc-hchanSize || size < 0 {
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 mem == 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.ptrdata == 0:
// Elements do not contain pointers.
// Allocate hchan and buf in one call.
c = (*hchan)(mallocgc