##文章参考:https://blog.csdn.net/guyan0319/article/details/90201405
1 goroutine之间通信go推荐使用chan的方式,chan本身是安全的有类型的
2 chan的数据结构在src/runtime/hchan中
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
}
3创建一个chan时chan的结构图. make(chan int ,3)->缓冲区为3
![chan1.JPG](https://static.studygolang.com/190828/9f58c480e10bc305196e12869278ea3e.JPG)
数据写入到buf中,qcount=1,
sendx=1,下一次存入的位置
rendx:如果buf不为空 rendx=sendx1-,如果为空=sendx
4 chan<-3时通道和roroutine的关系
4.1 写入通道时.锁住整个chan
4.2 确定写入.这时会尝试从recvq(等待读取的消息队列)中获取等待的goroutine,获取到直接赋值->gorotuine
4.3 如果recvq为空.确定缓冲区是否可用(未满),将数据写入到缓冲区
4.4 若果recvq为空.且缓冲区已满.把数据保存到当前的goroutine中(当前的goroutine就是想要写入的go).把这个goroutine加入到sendq(等待写入的队列),当前的goroutine挂起(就是阻塞 让出cpu)
4.5 写入完毕释放锁
4.6 逻辑图
![chan3.JPG](https://static.studygolang.com/190828/fab4bf7a90f6d9e2c2304164c79f0254.JPG)
5 <-chan 读取数据chan的状态
![chan2.JPG](https://static.studygolang.com/190828/0a10a696e087140636b31dcaf72cd24b.JPG)
读取后
![chan4.JPG](https://static.studygolang.com/190828/ff69b9e2f3a0526c96c731a9cb8278fe.JPG)
读取后buf为空sendx和recvx都是1
5.1读取数据时.先获取chan全局锁
5.2尝试从sendq等待队列中获取等待的goroutine
5.3如果有等待的goroutine,没有缓冲区,取出goroutine的数据.然后弄醒这个goroutine,释放锁.读取结束
5.4如果有等待的goroutine,有缓冲区(缓冲区已满),从缓冲区队首取出数据(),在从sendq中取出一个goroutine,弄醒这个 goroutine(这个goroutine就是写入数据时缓冲满了休眠的go),放入到buf的队尾.
5.5如没有等待的goroutine,且缓冲区有数据,直接读取缓冲区数据,结束读取释放锁
5.6如没有等待的goroutine,且没有缓冲区或缓冲区为空,将当前的goroutine加入sendq排队,进入睡眠,等待被写goroutine唤醒。结束读取释放锁
5.7图
![chan5.JPG](https://static.studygolang.com/190828/bc2c44b07c8885be7e14707a9081bdb5.JPG)
有疑问加站长微信联系(非本文作者))