1. 基本结构
type hchan struct {
qcount uint // 循环数组中的元素数量,长度
dataqsiz uint // 循环数组的大小,容量
// channel分为无缓冲和有缓冲channel两种
// 有缓冲的channel使用ring buffer(环形缓冲区)来缓存写入的数据,本质是循环数组
buf unsafe.Pointer // 指向底层循环数组的指针(环形缓冲区)
elemsize uint16 // 元素的大小
closed uint32 // 是否关闭的标志,0:未关闭,1:已关闭
elemtype *_type // channel中的元素类型
// 当下标超过数组容量后会回到第一个位置,所以需要有两个字段记录当前读和当前写的下标位置
sendx uint // 下一次写的位置
recvx uint // 下一次读的位置
// 尝试读/写channel时被阻塞的goroutine
recvq waitq // 读等待队列
sendq waitq // 写等待队列
// 互斥锁,保证读写channel时的并发安全问题
lock mutex
}
type waitq struct {
first *sudog
last *sudog
}
type sudog struct{
g *g
isSelect bool
next *sudog
prev *sudog
elem unsafe.Pointer //data element
...
}
recvq和sendq本质是链表,sudog 代表goroutine;
发送数据:
接收数据:
channel状态:
nil channel | close channel | 正常 channel | |
close | panic | panic | 正常关闭 |
读 | 阻塞 | 读对应的零值 | 阻塞或正常读取数据 |
写 | 阻塞 | panic | 阻塞或正常写入数据 |