go源码分析-> channel

针对go语言中chan的源码分析channel的机制

1:发送者流程
1:常规检查(发送一个已经关闭的chan会直接触发panic)
2:查看接受则阻塞队列中是否有sudog(对应的一个goroutine,注意是dequeue操作),如果有则直接发送消息到阻塞的goroutine(gp.param = unsafe.Pointer(sg),直接进行指针赋值,具体见chan.go/send函数),并且唤醒接受goroutine,goto 6
3:如果当前的阻塞队列没有满(sudog数量),则直接将发送的数据写入到发送的队列上(追加写),goto 6
4:当前的的阻塞队列满了(缓冲的数量在此处对于等待队列中goroutine的数量),生成一个sudog,将当前的goroutine加入的发送者队列中,阻塞当前goroutine,直接有消费者消费完消息
5:阻塞结束,释放当前的sudog
6:over

2:接受者流程
1:常规检查(接收一个已经关闭的chan会直接return)
2:查看接受则阻塞队列中是否有sudog(对应的一个goroutine),如果有则直接接受消息对于sudog的消息,goto 6
3:检查缓冲队列中是否有数据,有就直接取 goto 6; 否则继续
4:(进入阻塞,条件是1:发送队列中没有sudog,2:缓冲区没有数据)将当前sudog加入接受等待队列中,并阻塞当前goroutine(调用goparkunlock)
5:阻塞结束,释放当前的sudog
6:over

3:channel关闭流程
1:常规检查
2:遍历发送者/接受者队列中阻塞sudog,清空elem
3:唤醒对于sudog对于的goroutine

//sudog解释:
//一个sudog对应的一个发送/接受消息的goroutine
type sudog struct {
	g *g //当前的goroutine
	isSelect bool //是否阻塞
	next     *sudog //链表信息
	prev     *sudog
	elem     unsafe.Pointer // data element (may point to stack) //元素指针
	acquiretime int64
	releasetime int64
	ticket      uint32
	parent      *sudog // semaRoot binary tree
	waitlink    *sudog // g.waiting list or semaRoot 阻塞信息
	waittail    *sudog // semaRoot
	c           *hchan // channel
}

ps:至于有缓冲和无缓冲(缓冲区0)的区别,直接套流程就知道区别了。

ps:源码位置go/src/runtime/chan.go

你可能感兴趣的:(Go)