go version:1.12.5
文件 :src/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
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 mutex
}
-
qcount
当前队列中剩余的元素个数 -
dataqsize
环形队列长度,即可以存放的元素个数 -
buf
指向队列的内存,环形队列的指针 -
elemsize
每个元素的大小 -
closed
标识关闭状态 -
elemtype
元素类型 -
sendx
队列下标,指示元素写入时存放到队列中的位置,即队尾 -
recvx
队列下标,指示下一个被读取的元素在队列中的位置,即队首 -
recvq
等待读消息的协程队列,读取数据时,如果管道缓冲区为空或没有缓冲区,则当前协程会被阻塞,并被加入recvq队列. -
sendq
等待写消息的协程队列,向管道写入数据时,如果管道缓冲区已满或没有缓冲区,则当前协程会被阻塞,并被加入sendq队列. -
lock mutex
互斥锁, chan不允许并发读写,即一个管道同时仅允许被一个协程读写. -
注意:
sendq
和recvq
中的至少一个为空,但使用select
发送和接收的无缓冲通道上阻塞了单个goroutine
的情况除外,在这种情况下,sendq的长度而recvq仅受select语句的大小限制.
即:同一个协程使用select语句向管道一边写入一边读取,此时协程会分别位于两个队列
qcount> 0表示recvq为空.
qcount <dataqsiz表示sendq为空.
看图中结构体数据变化
![](https://img.haomeiwen.com/i17891001/402acf6760699e51.png)
![](https://img.haomeiwen.com/i17891001/5d98f21ef3aabd5a.png)
执行逻辑
-
向channel写入数据
image.png
-
从channel中读取数据
image.png
参考《GO专家编程》
网友评论