Go语言 Channel管道的源码分析及图解

Channel概述

Channel通过通信的方式在goroutine之间共享内存,是支撑Go语言高性能并发编程模型的重要结构,本文将分析Channel相关的创建、发送、接收、关闭函数的源代码。

ps:源代码只给出了重要逻辑核心部分

Channel结构体信息

Channel结构体为hchan ,源码如下:

type hchan struct {
   
	qcount   uint           // 元素个数
	dataqsiz uint           // 循环队列的长度
	buf      unsafe.Pointer // 缓冲区数据指针
	elemsize uint16         //元素类型大小
	closed   uint32         //是否关闭标志位
	elemtype *_type 		// 元素类型
	sendx    uint   		// 发送数据的发送偏移位置(缓冲区中)
	recvx    uint   		// 接收数据的接收偏移位置(缓冲区中)
	recvq    waitq    		// 阻塞的发送Goroutine列表,链表形式,后来的协程在链表尾部
	sendq    waitq  		// 阻塞的接收Goroutine列表
	lock mutex				//锁
}

Channel创建

创建chan的函数为makechan,判断是否创建缓冲区。

func makechan(t *chantype, size int) *hchan {
   
  	//一些元素检查部分,略过
	elem := t.elem
	mem, overflow := math.MulUintptr(elem.size, uintptr(size))
	var c *hchan
	switch {
   
	case mem == 0:      //无缓冲区
		c = (*hchan)(mallocgc(hchanSize, nil, true))
		c.buf = c.raceaddr()   
	case elem.ptrdata == 0:   //类型不是指针类型, 分配一块连续的内存空间
		c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
		c.buf = add(unsafe.Pointer(c), hchanSize)  
	default:    //默认分配hchan和缓冲区空间
		c = new(hchan)
		c.buf = mallocgc(mem, elem, true)
	}
	//初始化信息
	c.elemsize = uint16(elem.size)
	c.elemtype = elem
	c.dataqsiz = uint(size)
	lockInit(&c.lock, lockRankHchan)
	}
	return c
}

chansend发送

发送函数为chansend,主体分为3个部分:

  1. 如果存在接收方,直接发送
  2. 缓冲空间有剩余时,写入缓冲空间
  3. 上述都不满足时,阻塞发送,等待其他Goroutine接收操作
func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
   
	//一些元素检查部分,略过
	lock(&c.lock)
	if c.closed != 0 {
       //如果发送时管道已经关闭,直接panic
		unlock(&c.lock)
		panic(plainError("send on closed channel"))
	}
	
	//第一个判断:如果接收队列中有协程在等待,那么直接发送数据
	//dequeue()取链表头部元素,也就是最先陷入等待的Goroutine
	if sg := c.recvq.dequeue(); sg != nil {
          		
		send(c, sg, ep, func() {
    unlock(&c.lock) }, 3)   //send函数见下面分析
		//
		return true
	}
	
	//第二个判断:缓冲区如果有剩余,则将数据写入缓冲区(无缓冲区channel跳过)
	if c.qcount < c.dataqsiz {
   
		qp :
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值