常见的暂停操作
GoSched - 见于抢占调度
这种操作会把当前G状态从running改回runnable,再放回全局队列里, 自己则是通过一次Schedule再找个任务做
GoPark - 见于WaitGroup
与GoSched差不多, 都是要把状态改成runable以后自己通过sched找个任务做, 区别是被拿下来的G并不会被被放到队列里, 如果你不主动去再重启它的话它永远也不会再运行了
运行它的办法是
GoReady
函数, 这个函数会直接让G去往P的run_next
位置
Notesleep - 见于休眠的M:
stopm()
之前两种都是围绕G展开的, 这一种则是针对线程的, 整个线程直接被冻结, 直到被notewakeup函数叫醒
被认为是"很灵活", 使用FUTEX技术实现
StopTheWorld - 见于GC
名气太大不用介绍, 关于stw的代码其实在调度过程里穿插的到处都是, 目的是让调度过程尽早响应GC停止一切的命令. 所有的G该停就停,M改休眠的休眠, 这种操作是怎么做到的呢?
停G: 通过设置抢占位(stackpreempt/复习G栈内容), 使得G在下一次函数调用的时候进入
morestack
开始状态检查, 进而GC沉睡停M: 设置全局变量
gcwaiting=1
这个变量会在M下一次执行schedule()
的时候发挥作用, 让M进入沉睡状态停P: 将所有的P,包含空闲的,以及正在SYSCALL的P全都暂停, 遍历全局P列表,schedt.allp[i],逐一发送抢占信号
最后会通过StartTheWorld再将所有P叫起来工作, 原则是找到这个P之前所关联的M, 将这个沉睡的M叫起来, 如果这个P之前没关联M, 那么就创建一个新M来接纳P
Last updated
Was this helpful?