golang 源码剖析(6): 通道

本文详细剖析了Go语言中的通道(channel)特性,包括通道的创建、收发操作、关闭以及select的使用。通道是Go实现并发处理的关键,通过通信来共享数据。文章介绍了通道的基本操作,如无缓冲和有缓冲通道的发送与接收过程,以及在通道关闭后的处理。同时,还探讨了select语句的实现细节和竞争条件的避免策略。
摘要由CSDN通过智能技术生成

简介

通道(channel) 是Go实现CSP并发模型的关键, 鼓励用通信来实现数据共享。 Dont’ communicate by sharing memory, share memory by communicating.
CSP: Communicating Sequential Process

创建

chan.go中 hchan的结构

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 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
}

type waitq struct {
	first *sudog
	last  *sudog
}

makechan: 这里先做了一些元素大小,队列大小检查。受垃圾回收器的限制,如果包含指针类型,则缓冲槽需单独分配内存,否则可一次性分配,调整buf的指针,最后设置size等属性

func makechan(t *chantype, size int) *hchan {
	elem := t.elem
	// compiler checks this but be safe.
	if elem.size >= 1<<16 { //限制chan的元素大小
		throw("makechan: invalid channel element type")
	}
	mem, overflow := math.MulUintptr(elem.size, uintptr(size)) //检查是否溢出
	if overflow || mem > maxAlloc-hchanSize || size < 0 {
		panic(plainError("makechan: size out of range"))
	}
	var c *hchan
	switch {
	case mem == 0:
		// Queue or element size is zero.
		c = (*hchan)(mallocgc(hchanSize, nil, true))
		// Race detector uses this location for synchronization.
		c.buf = c.raceaddr()
	case elem.ptrdata == 0:
		// Elements do not contain pointers.
		// Allocate hchan and buf in one call.
		c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
		c.buf = add(unsafe.Pointer(c), hchanSize)
	default:
		// Elements contain pointers.
		c = new(hchan)
		c.buf = mallocgc(mem, elem, true)
	}

收发

这里用sudog用来保存收发队列,其中包含一个元素和g的指针,这里也实现了cache,central那一套缓存体系.
acquireSudog获取sudog和releaseSudog释放sudog, 大致流程也是先从本地p获取,接着再去sched.sudogcache中获取.

type sudog struct {
	g *g
	elem     unsafe.Pointer // data element (may point to stack)
}
type p struct {
	sudogcache []*sudog
	sudogbuf   [128]*sudog
}
type schedt struct {
	// Central cache of sudog structs.
	sudoglock  mutex
	sudogcache *sudog
}

发送

在go1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值