// compiler checks this but be safe. if elem.size >= 1<<16 { throw("makechan: invalid channel element type") } if hchanSize%maxAlign != 0 || elem.align > maxAlign { throw("makechan: bad alignment") } // 计算为元素分配的大小 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: // 当分配的大小为0时,只用在内存中分配hchan结构体的大小即 可。 c = (*hchan)(mallocgc(hchanSize, nil, true)) c.buf = c.raceaddr() case elem.ptrdata == 0: // 当通道的元素中不包含指针时,连续分配hchan结构体大小+size 元素大小。 c = (*hchan)(mallocgc(hchanSize+mem, nil, true)) c.buf = add(unsafe.Pointer(c), hchanSize) default: // 当通道的元素中包含指针时,需要单独分配内存空间,因为当元 素中包含指针时,需要单独分配空间才能正常进行垃圾回收。 c = new(hchan) c.buf = mallocgc(mem, elem, true) }
funcchansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr)bool { // 通过为nil,休眠 if c == nil { if !block { returnfalse } gopark(nil, nil, waitReasonChanSendNilChan, traceEvGoStop, 2) throw("unreachable") }
// ---省略代码--- // 加锁 lock(&c.lock)
// 通道被关闭,直接panic if c.closed != 0 { unlock(&c.lock) panic(plainError("send on closed channel")) } // 存在等待的接收者时,通过 runtime.send 直接将数据发送给阻塞的接收者 if sg := c.recvq.dequeue(); sg != nil { // Found a waiting receiver. We pass the value we want to send // directly to the receiver, bypassing the channel buffer (if any). send(c, sg, ep, func() { unlock(&c.lock) }, 3) returntrue } // 当缓冲区存在空余空间时,将发送的数据写入 Channel 的缓冲区 if c.qcount < c.dataqsiz { // Space is available in the channel buffer. Enqueue the element to send. qp := chanbuf(c, c.sendx) if raceenabled { racenotify(c, c.sendx, nil) } typedmemmove(c.elemtype, qp, ep) c.sendx++ if c.sendx == c.dataqsiz { c.sendx = 0 } c.qcount++ unlock(&c.lock) returntrue }
funcchansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr)bool { // ... if sg := c.recvq.dequeue(); sg != nil { // Found a waiting receiver. We pass the value we want to send // directly to the receiver, bypassing the channel buffer (if any). send(c, sg, ep, func() { unlock(&c.lock) }, 3) returntrue } // ... }