Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > golang sudog

golang sudog指的是什么

作者:动态一时爽,重构火葬场

sudog代表在等待队列中的goroutine,比如channel发送接受,由于goroutine和同步对象的关系是多对多,因此需要sudog映射,本文重点介绍golang sudog指的是什么,感兴趣的朋友一起看看吧

sudog代表在等待队列中的goroutine,比如channel发送接受。由于goroutine和同步对象的关系是多对多,因此需要sudog映射

type sudog struct {
  // 指向的goroutine
	g *g
  // 指向前后sudog的指针
	next *sudog
	prev *sudog
  // 指向数据
	elem unsafe.Pointer // data element (may point to stack)
	// The following fields are never accessed concurrently.
	// For channels, waitlink is only accessed by g.
	// For semaphores, all fields (including the ones above)
	// are only accessed when holding a semaRoot lock.
  // 获取时间
	acquiretime int64
  // 释放时间
	releasetime int64
  // 作为队列元素的标识
	ticket      uint32
	// isSelect indicates g is participating in a select, so
	// g.selectDone must be CAS'd to win the wake-up race.
	isSelect bool
	// success indicates whether communication over channel c
	// succeeded. It is true if the goroutine was awoken because a
	// value was delivered over channel c, and false if awoken
	// because c was closed.
	success bool
	parent   *sudog // semaRoot binary tree
	waitlink *sudog // g.waiting list or semaRoot
	waittail *sudog // semaRoot
	c        *hchan // channel
}

acquireSudog()

func acquireSudog() *sudog {
  // 增加m的锁,防止垃圾回收在此期间被调用
	mp := acquirem()
	pp := mp.p.ptr()
 	// 如果本地缓存为空
	if len(pp.sudogcache) == 0 {
		lock(&sched.sudoglock)
    // 从中心缓存迁移至多一半本地缓存容量的缓存项到本地缓存
		for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {
			s := sched.sudogcache
			sched.sudogcache = s.next
			s.next = nil
			pp.sudogcache = append(pp.sudogcache, s)
		}
		unlock(&sched.sudoglock)
    // 若本地缓存仍为空,则新建缓存项
		if len(pp.sudogcache) == 0 {
			pp.sudogcache = append(pp.sudogcache, new(sudog))
		}
	}
  // 从本地缓存中取出最后一个缓存项返回
	n := len(pp.sudogcache)
	s := pp.sudogcache[n-1]
	pp.sudogcache[n-1] = nil
	pp.sudogcache = pp.sudogcache[:n-1]
	if s.elem != nil {
		throw("acquireSudog: found s.elem != nil in cache")
	}
  // 减少m的锁,允许垃圾回收调用
	releasem(mp)
	return s
}

releaseSudog()

func releaseSudog(s *sudog) {
  // 判断sudog各项数据、状态是否正确
	if s.elem != nil {
		throw("runtime: sudog with non-nil elem")
	}
	if s.isSelect {
		throw("runtime: sudog with non-false isSelect")
	}
	if s.next != nil {
		throw("runtime: sudog with non-nil next")
	}
	if s.prev != nil {
		throw("runtime: sudog with non-nil prev")
	}
	if s.waitlink != nil {
		throw("runtime: sudog with non-nil waitlink")
	}
	if s.c != nil {
		throw("runtime: sudog with non-nil c")
	}
	gp := getg()
	if gp.param != nil {
		throw("runtime: releaseSudog with non-nil gp.param")
	}
	mp := acquirem() // avoid rescheduling to another P
	pp := mp.p.ptr()
  // 如果本地缓存满了,就迁移至多一半容量缓存项到中心缓存
	if len(pp.sudogcache) == cap(pp.sudogcache) {
		// Transfer half of local cache to the central cache.
		var first, last *sudog
		for len(pp.sudogcache) > cap(pp.sudogcache)/2 {
			n := len(pp.sudogcache)
			p := pp.sudogcache[n-1]
			pp.sudogcache[n-1] = nil
			pp.sudogcache = pp.sudogcache[:n-1]
			if first == nil {
				first = p
			} else {
				last.next = p
			}
			last = p
		}
		lock(&sched.sudoglock)
    // 将迁移出来的本地缓存链表直接挂到中心缓存中
		last.next = sched.sudogcache
		sched.sudogcache = first
		unlock(&sched.sudoglock)
	}
  // 将释放的sudog添加到本地缓存
	pp.sudogcache = append(pp.sudogcache, s)
	releasem(mp)
}

到此这篇关于golang sudog是什么?的文章就介绍到这了,更多相关golang sudog内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

阅读全文