返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

7.3 执行

发布于 2024-10-12 19:16:00 字数 2225 浏览 0 评论 0 收藏 0

创建专门的 goroutine 用于执行终结函数。

// mfinal.go

// A single goroutine runs all finalizers for a program, sequentially.
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.

func SetFinalizer(obj any, finalizer any) {

	// make sure we have a finalizer goroutine
	createfing()
}
var fingCreate uint32

func createfing() {
	// start the finalizer goroutine exactly once
	if fingCreate == 0 && atomic.Cas(&fingCreate, 0, 1) {
		go runfinq()
	}
}

两个全局标记,分别代表唤醒和休眠。

// mfinal.go

var fingwait bool
var fingwake bool

var fing *g        // goroutine that runs finalizers
// mfinal.go

// This is the goroutine that runs all of the finalizers
func runfinq() {
    
	for {
		// 扣下 finq 队列。
		fb := finq
		finq = nil
        
        // 队列空,休眠。
		if fb == nil {
			gp := getg()
            
			fing = gp         // !!!            
			fingwait = true   // !!!
            
			goparkunlock(&finlock, waitReasonFinalizerWait, traceEvGoBlock, 1)
			
            continue
		}
        
        // 遍历队列。
		for fb != nil {
            
            // 遍历单个 finblock 内终结器数组。
			for i := fb.cnt; i > 0; i-- {
                
                // 提取一个 finalizer。
				f := &fb.fin[i-1]

                // 执行终结函数。
				fingRunning = true
				reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz), uint32(framesz), &regs)
				fingRunning = false

				f.fn = nil
				f.arg = nil
				f.ot = nil
				atomic.Store(&fb.cnt, i-1)
			}
            
            // 下一 finblock。
			next := fb.next
            
            // 当前 block 放回缓存(finc)。
			fb.next = finc
			finc = fb
            
			fb = next
		}
	}
}

唤醒

在 schedule/findrunnable 里,会检查并尝试唤醒。

// proc.go

func findrunnable() (gp *g, inheritTime bool) {
    
    // 当 queuefinalizer 添加函数到队列时,设置 fingwake = true。
    
	if fingwait && fingwake {
        
        // 获取 fing G 并唤醒。
		if gp := wakefing(); gp != nil {
			ready(gp, 0, true)
		}
	}    
}
// mfinal.go

func wakefing() *g {
	var res *g
    
	if fingwait && fingwake {
		fingwait = false
		fingwake = false
		res = fing
	}
    
	return res
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文