数据结构
类似于管道,可以并发读写。不可以向已关闭chan写入数据。
// 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
sendx uint // send index
recvx uint // receive index
elemsize uint16
closed uint32
elemtype *_type // element type
// 读写等待队列
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
}
实现
直接搬运代码,专注细节容易绕晕。大致每个功能需要考虑几种边界条件
阻塞/非阻塞
缓冲区为空/非空
缓冲区满/非满
读写等待队列空/非空
chan为nil/非nil
1、单chan读/写(runtime/chan.go:chanrecv/chansend)
2、关闭chan(runtime/chan.go:closechan)。加锁;唤醒读/写等待队列全部任务;解锁
3、多个chan同时读/写(runtime/select.go:selectgo)。大致思路就是打乱case顺序;对全部chan加锁;遍历找出第一个读/写准备好的任务;逆序解锁