返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

4.4.2 唤醒

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

在唤醒其他 MP 出来工作前,先检查是否有处于自旋状态的 MP。

// proc.go

// Tries to add one more P to execute G's.
// Called when a G is made runnable (newproc, ready).

func wakep() {
    
    // 必须有闲置的 P。
    if atomic.Load(&sched.npidle) == 0 {
        return
    }

    // 如果失败,表示有处于自旋状态的 M/P。
    if atomic.Load(&sched.nmspinning) != 0 || !atomic.Cas(&sched.nmspinning, 0, 1) {
        return
    }
    
    startm(nil, true)
}

用 wakep 唤醒或新建 M 时,会设置自旋状态。表示当前 MP 正积极查找 runnable G,其他人就不要掺合了。

自旋状态要么被 schedule 调用 resetspinning 解除,要么类似 findrunnable 在 stopm 前自行解除。

新建(newm)以初始化函数(mspinning)设置自旋状态;被唤醒的,在 startm 中直接设置。

// proc.go

// Schedules some M to run the p (creates an M if necessary).
// If p==nil, tries to get an idle P, if no idle P's does nothing.

func startm(_p_ *p, spinning bool) {
    
    // 如果没有传入 P,则试图绑定空闲 P。
    if _p_ == nil {
        _p_ = pidleget()
        
        // 没有空闲 P,解除自旋计数,放弃本次唤醒。
        if _p_ == nil {
            if spinning {
                atomic.Xadd(&sched.nmspinning, -1)
            }
            
            return
        }
    }
    
    // 获取休眠 M。
    mp := mget()
    
    // 获取失败,新建。
    if mp == nil {
        
        // 线程初始化函数,用于设置自旋状态。
        var fn func()    
        if spinning {
            fn = mspinning
        }
        
        newm(fn, _p_, id)
        return
    }
    
    // 传递 P,唤醒休眠的 M。
    mp.spinning = spinning
    mp.nextp.set(_p_)
    notewakeup(&mp.park)
}
func mspinning() {
    getg().m.spinning = true
}

nextp

M 有 p 和 nextp 两个属性。

M.p 是正式绑定;nextp 临时存储,稍后绑定。

// runtime2.go

type m struct {
    p      puintptr   // attached p for executing go code (nil if not executing go code)
    nextp  puintptr
}

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

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

发布评论

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