chansend中gp.param相关疑问

来源:1-9 神奇的内置数据结构

tan_beta

2021-06-30 11:51:59

在chansend函数中,如果chan被阻塞,生成sudog得时候会将gp.param置为nil,然后挂起当前gp,当被唤醒之后,继续执行,这个时候会检查gp.param是否为nil,如果为nil会panic;否则将gp.param置为nil。那么是在何处给gp.param赋值得呢(因为挂起之前将gp.param置为了nil了)?代码如下:

	gp := getg()
	mysg := acquireSudog()
	mysg.releasetime = 0
	if t0 != 0 {
		mysg.releasetime = -1
	}
	// No stack splits between assigning elem and enqueuing mysg
	// on gp.waiting where copystack can find it.
	mysg.elem = ep
	mysg.waitlink = nil
	mysg.g = gp
	mysg.isSelect = false
	mysg.c = c
	gp.waiting = mysg
	gp.param = nil
	c.sendq.enqueue(mysg)
	// Signal to anyone trying to shrink our stack that we're about
	// to park on a channel. The window between when this G's status
	// changes and when we set gp.activeStackChans is not safe for
	// stack shrinking.
	atomic.Store8(&gp.parkingOnChan, 1)
	gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceEvGoBlockSend, 2)
	// Ensure the value being sent is kept alive until the
	// receiver copies it out. The sudog has a pointer to the
	// stack object, but sudogs aren't considered as roots of the
	// stack tracer.
	KeepAlive(ep)

	// someone woke us up.
	if mysg != gp.waiting {
		throw("G waiting list is corrupted")
	}
	gp.waiting = nil
	gp.activeStackChans = false
	if gp.param == nil {
		if c.closed == 0 {
			throw("chansend: spurious wakeup")
		}
		panic(plainError("send on closed channel"))
	}
	gp.param = nil
写回答

1回答

Xargin

2021-06-30

在 chanrecv 里面:


if sg := c.sendq.dequeue(); sg != nil {
// Found a waiting sender. If buffer is size 0, receive value
  // directly from sender. Otherwise, receive from head of queue
  // and add sender's value to the tail of the queue (both map to
  // the same buffer slot because the queue is full).
  recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
return true, true
}


然后 recv 里面

gp.param = unsafe.Pointer(sg)


0
han_beta
hp dir="ltr">啊,对哈。。脑袋没转过来,谢谢曹大

h021-06-30
共1条回复

Go高级工程师实战营

慕课网与 GoCN 社区官方联手打造,定义行业Go高级人才培养标准,4个月,快速晋升为P6+/D7级高级人才。

458 学习 · 266 问题

查看课程