【go】channel结构体源码和读写和关闭过程

  • 简而言之,channel维护了一个带指针的接受和发送的队列,其中包含mutex锁保证并发安全,数据类型,元素个数,元素大小,channel状态
  • 然后读写操作,先看队列是否可以取出,然后看缓冲区,最后放入接受/发送队列
  • 关闭就是唤醒所有goroutine然后将他们的标志位设为1,表示关闭,以后有人访问就是nil

结构体源码

type hchan struct {
    qcount   uint           // 当前队列中元素的数量
    dataqsiz uint           // 缓冲区大小,即可以缓存的元素数量
    buf      unsafe.Pointer // 指向队列的缓冲区
    elemsize uint16         // 每个元素的大小
    closed   uint32         // channel 是否已关闭的标志
    elemtype *_type         // channel 中元素的类型
    sendx    uint           // 下一次发送元素的位置
    recvx    uint           // 下一次接收元素的位置
    recvq    waitq          // 等待接收的 goroutine 队列
    sendq    waitq          // 等待发送的 goroutine 队列
    lock     mutex          // 用于保护 channel 的互斥锁
}

发送数据

当一个 goroutine 要向 channel 中发送数据时,它会执行 chansend 函数。

  1. 这个函数首先会对 channel 进行加锁,然后判断是否有等待接收的 goroutine
  2. 如果有,则直接将数据发送给它;否则,如果缓冲区未满,则将数据放入缓冲区,队列中元素数量加一;
  3. 如果队列已满,则将当前 goroutine 加入等待发送的 goroutine 队列中,并阻塞它,等待其他 goroutine 接收数据。

接受数据

当一个 goroutine 要从 channel 中接收数据时,它会执行 src/runtime/chan.go 中的 chanrecv 函数。

  1. 这个函数也会对 channel 进行加锁,然后判断是否有等待发送的 goroutine,如果有,则直接从它那里接收数据;
  2. 否则,如果缓冲区元素的数量大于 0,则从缓冲区中取出一个元素,并将队列中元素数量减一。
  3. 如果缓冲区为空,则将当前 goroutine 加入等待接收的 goroutine 队列中,并阻塞它,等待其他 goroutine 发送数据。

关闭channel

当一个 goroutine 要关闭 channel 时,它会执行 src/runtime/chan.go 中的 closechan 函数。

  1. 这个函数会对 channel 进行加锁,然后将 closed 标志置为 1,表示 channel 已经关闭。
  2. 然后遍历等待发送和等待接收的 goroutine 队列,将它们全部唤醒,并返回一个特殊的值来表示 channel 已经关闭。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值