【go】chan底层原理

7 篇文章 0 订阅
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 // 元素类型指针
	sendx    uint   // 发送操作的下标
	recvx    uint   // 接受操作的下标
	recvq    waitq  // 接受等待队列
	sendq    waitq  // 发送等待队列

	// 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是golang中协程之间通信的结构,所以必定要有一个锁lock来控制并发
  • 有缓冲的chan需要使用buf来指向缓冲区的位置
  • qcount记录队列中的总数据量,dataqsiz用来记录队列的容量,elemtype用来记录元素类型,便于内存复制、垃圾回收等等操作
  • 因为chan的通信操作注定要有等待的情况,所以需要recvq,sendq用来存储等待发送或接受的协程,recvx,sendx用来记录发接受或发送操作的下标。

recvq和sendq的类型waitq中包含了头尾两个sudog类型的变量,sudog为通用的等待队列结构。

type waitq struct {
	first *sudog
	last  *sudog
}

type sudog struct {
	// The following fields are protected by the hchan.lock of the
	// channel this sudog is blocking on. shrinkstack depends on
	// this for sudogs involved in channel ops.

	g *g

	next *sudog
	prev *sudog
	elem unsafe.Pointer // data element (may point to stack)

	// The following fields are never accessed concurrently.
	// For channels, waitlink is only accessed by g.
	// For semaphores, all fields (including the ones above)
	// are only accessed when holding a semaRoot lock.

	acquiretime int64
	releasetime int64
	ticket      uint32

	// isSelect indicates g is participating in a select, so
	// g.selectDone must be CAS'd to win the wake-up race.
	isSelect bool

	// success indicates whether communication over channel c
	// succeeded. It is true if the goroutine was awoken because a
	// value was delivered over channel c, and false if awoken
	// because c was closed.
	success bool

	parent   *sudog // semaRoot binary tree
	waitlink *sudog // g.waiting list or semaRoot
	waittail *sudog // semaRoot
	c        *hchan // channel
}

这是一个包含next和prev的双向链表,里面就包含了等待的chan信息

chan的元素缓冲区就是一个数组,通过元素下标的改变实现环形结构

		if c.sendx == c.dataqsiz {
			c.sendx = 0
		}

在执行发送操作的时候,如果接受等待队列中存在等待的协程,则直接将元素发送给等待协程,从而绕过缓冲区,避免了不必要的存取操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值