聊聊Goroutine-结构体、全局变量(三)

161 篇文章 12 订阅

先来看看goroutine调度器相关重要结构体,位于Go源代码下runtime/runtime2.go。

因其成员变量极多,细节极其复杂,所以只看与调度器相关的成员变量。

stack:记录goroutine使用的栈信息,包括栈顶和栈底的位置信息。

// Stack describes a Go execution stack.// The bounds of the stack are exactly [lo, hi),// with no implicit data structures on either side.//用于记录goroutine使用的栈的起始和结束位置type stack struct {      lo uintptr    // 栈顶,指向内存低地址    hi uintptr    // 栈底,指向内存高地址}

gobuf:保存goroutine的调度信息,主要是CPU几个寄存器的值。

type gobuf struct {    // The offsets of sp, pc, and g are known to (hard-coded in) libmach.    //    // ctxt is unusual with respect to GC: it may be a    // heap-allocated funcval, so GC needs to track it, but it    // needs to be set and cleared from assembly, where it's    // difficult to have write barriers. However, ctxt is really a    // saved, live register, and we only ever exchange it between    // the real register and the gobuf. Hence, we treat it as a    // root during stack scanning, which means assembly that saves    // and restores it doesn't need write barriers. It's still    // typed as a pointer so that any other writes from Go get    // write barriers.    sp   uintptr  // 保存CPU的rsp寄存器的值    pc   uintptr  // 保存CPU的rip寄存器的值    g    guintptr // 记录当前这个gobuf对象属于哪个goroutine    ctxt unsafe.Pointer     // 保存系统调用的返回值,因为从系统调用返回之后如果p被其它工作线程抢占,    // 则这个goroutine会被放入全局运行队列被其它工作线程调度,其它线程需要知道系统调用的返回值。    ret  sys.Uintreg      lr   uintptr     // 保存CPU的rip寄存器的值    bp   uintptr // for GOEXPERIMENT=framepointer}

g:用于代表一个goroutine,保存了goroutine的所有信息,包括栈。

// 前文所说的g结构体,它代表了一个goroutinetype g struct {    // Stack parameters.    // stack describes the actual stack memory: [stack.lo, stack.hi).    // stackguard0 is the stack pointer compared in the Go stack growth prologue.    // It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.    // stackguard1 is the stack pointer compared in the C stack growth prologue.    // It is stack.lo+StackGuard on g0 and gsignal stacks.    // It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).     // 记录该goroutine使用的栈    stack       stack   // offset known to runtime/cgo    // 下面两个成员用于栈溢出检查,实现栈的自动伸缩,抢占调度也会用到stackguard0    stackguard0 uintptr // offset known to liblink    stackguard1 uintptr // offset known to liblink    ......     // 此goroutine正在被哪个工作线程执行    m              *m      // current m; offset known to arm liblink    // 保存调度信息,主要是几个寄存器的值    sched          gobuf     ......    // schedlink字段指向全局运行队列中的下一个g,    //所有位于全局运行队列中的g形成一个链表    schedlink      guintptr    ......    // 抢占调度标志,如果需要抢占调度,设置preempt为true    preempt        bool       // preemption signal, duplicates stackguard0 = stackpreempt   ......}

m:用于代表工作线程,保存自身使用栈信息和当前正在运行goroutine及m绑定的p。

type m struct {    // g0主要用来记录工作线程使用的栈信息,在执行调度代码时需要使用这个栈    // 执行用户goroutine代码时,使用用户goroutine自己的栈,调度时会发生栈的切换    g0      *g     // goroutine with scheduling stack    // 通过TLS实现m结构体对象与工作线程之间的绑定    tls           [6]uintptr   // thread-local storage (for x86 extern register)    mstartfn      func()    // 指向工作线程正在运行的goroutine的g结构体对象    curg          *g       // current running goroutine    // 记录与当前工作线程绑定的p结构体对象    p             puintptr // attached p for executing go code (nil if not executing go code)    nextp         puintptr    oldp          puintptr // the p that was attached before executing a syscall       // spinning状态:表示当前工作线程正在试图从其它工作线程的本地运行队列偷取goroutine    spinning      bool // m is out of work and is actively looking for work    blocked       bool // m is blocked on a note    // 没有goroutine需要运行时,工作线程睡眠在这个park成员上,    // 其它线程通过这个park唤醒该工作线程    park          note    // 记录所有工作线程的一个链表    alllink       *m // on allm    schedlink     muintptr    // Linux平台thread的值就是操作系统线程ID    thread        uintptr // thread handle    freelink      *m      // on sched.freem    ......}

p:用于保存工作线程执行Go代码所必需的资源,如goroutine运行队列以及内存分配用到的缓存等信息。

type p struct {    lock mutex    status       uint32 // one of pidle/prunning/...    link            puintptr    schedtick   uint32     // incremented on every scheduler call    syscalltick  uint32     // incremented on every system call    sysmontick  sysmontick // last tick observed by sysmon    m                muintptr   // back-link to associated m (nil if idle)    ......    // Queue of runnable goroutines. Accessed without lock.    //本地goroutine运行队列    runqhead uint32  // 队列头    runqtail uint32     // 队列尾    runq     [256]guintptr  //使用数组实现的循环队列    // runnext, if non-nil, is a runnable G that was ready'd by    // the current G and should be run next instead of what's in    // runq if there's time remaining in the running G's time    // slice. It will inherit the time left in the current time    // slice. If a set of goroutines is locked in a    // communicate-and-wait pattern, this schedules that set as a    // unit and eliminates the (potentially large) scheduling    // latency that otherwise arises from adding the ready'd    // goroutines to the end of the run queue.    runnext guintptr    // Available G's (status == Gdead)    gFree struct {        gList        n int32    }    ......}

schedt:保存调度器的状态信息以及goroutine的全局运行队列。

type schedt struct {    // accessed atomically. keep at top to ensure alignment on 32-bit systems.    goidgen  uint64    lastpoll uint64    lock mutex    // When increasing nmidle, nmidlelocked, nmsys, or nmfreed, be    // sure to call checkdead().    // 由空闲的工作线程组成链表    midle        muintptr // idle m's waiting for work    // 空闲的工作线程的数量    nmidle       int32    // number of idle m's waiting for work    nmidlelocked int32    // number of locked m's waiting for work    mnext        int64    // number of m's that have been created and next M ID    // 最多只能创建maxmcount个工作线程    maxmcount    int32    // maximum number of m's allowed (or die)    nmsys        int32    // number of system m's not counted for deadlock    nmfreed      int64    // cumulative number of freed m's    ngsys uint32 // number of system goroutines; updated atomically    // 由空闲的p结构体对象组成的链表    pidle      puintptr // idle p's    // 空闲的p结构体对象的数量    npidle     uint32    nmspinning uint32 // See "Worker thread parking/unparking" comment in proc.go.    // Global runnable queue.    // goroutine全局运行队列    runq     gQueue    runqsize int32    ......    // Global cache of dead G's.    // gFree是所有已经退出的goroutine对应的g结构体对象组成的链表    // 用于缓存g结构体对象,避免每次创建goroutine时都重新分配内存    gFree struct {        lock          mutex        stack        gList // Gs with stacks        noStack   gList // Gs without stacks        n              int32    }    ......}

再来看看goroutine调度器相关重要全局变量。

allgs      []*g     // 保存所有的gallm       *m    // 所有的m构成的一个链表,包括下面的m0allp       []*p    // 保存所有的p,len(allp) == gomaxprocsncpu       int32   // 系统中cpu核的数量,程序启动时由runtime代码初始化gomaxprocs int32   // p的最大值,默认等于ncpu,但可以通过GOMAXPROCS修改sched      schedt     // 调度器结构体对象,记录了调度器的工作状态m0         m       // 代表进程的主线程g0         g        // m0的g0,也就是m0.g0 = &g0

上述变量在程序初始化时,全部会被初始化为0值,指针会被初始化为nil指针,切片会被初始化为nil切片,int被初始化为数字0,结构体的所有成员变量按其数据类型初始化为自身类型的0值,所以在程序刚启动时,allgs、allm,allp都不包含任何g、m、p。

以上仅为个人观点,不一定准确,能帮到各位那是最好的。

好啦,到这里本文就结束了,喜欢的话就来个三连击吧。

扫码关注公众号,获取更多优质内容。

  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luyaran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值