模型
三部分组成:
定义
在 runtime 的chan.go中- type hchan struct {
- qcount uint
- dataqsiz uint
- buf unsafe.Pointer
- elemsize uint16
- elemtype *_type // element type
- // 上面的这几个组成了一个环形缓存区
- closed uint32 // 关闭状态
- // 下面4个组成了2个队列 g的
- 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
- lock mutex // 锁,用于在操作 channel的 元素时候,保证并发安全
- }
复制代码 特殊缓存区
 - qcount 已经存储的个数
- dataqsiz 环形队列缓存的容量,即允许缓存的消息最大个数
- buf 指向这个缓存区的地址
- elemsize 元素的大小
- elemtype 元素的类型
复制代码 设计成这样,主要目的不需要gc来清理,因为环形机构,会自动把删除数据内存给占了。
环形缓存可以大幅降低GC的开销
两个队列
这里还要看下 waitq 的定义- type waitq struct {
- first *sudog
- last *sudog
- }
- // 在sema中也有用到,就g结构体的封装
- type sudog struct {
- g *g
- next *sudog
- prev *sudog
- elem unsafe.Pointer // 接受参数的地址
- // 当是接收g时候,如果有缓存中有数据,直接把数据拷贝到这个地址
复制代码 }
注意:这里的sendx 并不是指向发送队列中的g,而且发送队列应该写入环形缓存区的index,
同理,recvx也是,指向接受数据的g,应该从缓冲区的那个index取数据
互斥锁
互斥锁并不是排队发送/接收数据
不是让发送和接收队列来排队的,这些发送和接收数据的队列,休眠也不是在锁的sema里
互斥锁保护的hchan结构体本身
所以, Channel并不是无锁的
状态值
0为开启、1为关闭- 当一个关闭的channel,再往里写或者重复关闭、就会panic。但是可以读。
复制代码 发送数据
[code]c |