上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.2.2 StopTheWorld
STW 面向全局设置停止状态,让所有 P 停止任务执行。
// proc.go func stopTheWorldWithSema() { lock(&sched.lock) sched.stopwait = gomaxprocs // 停止计数器。 atomic.Store(&sched.gcwaiting, 1) // 会被 schedule 看到,引发 gcstopm 调用。 preemptall() // 向所有运行中的 G 发出抢占信号。 // 停止当前 P。 _g_.m.p.ptr().status = _Pgcstop sched.stopwait-- // 回收 syscall P。 for _, p := range allp { s := p.status if s == _Psyscall && atomic.Cas(&p.status, s, _Pgcstop) { sched.stopwait-- } } // 停止 idle P。 for { p := pidleget() if p == nil { break } p.status = _Pgcstop sched.stopwait-- } wait := sched.stopwait > 0 unlock(&sched.lock) // 等待所有 P 停止。 if wait { for { // 等待 100us。如被 notewakeup,那么 notetsleep 返回 true。 if notetsleep(&sched.stopnote, 100*1000) { noteclear(&sched.stopnote) break } preemptall() } } }
所设置状态在 schedule 里被检测到。
// proc.go func schedule() { top: if sched.gcwaiting != 0 { gcstopm() goto top } }
// proc.go // Stops the current m for stopTheWorld. // Returns when the world is restarted. func gcstopm() { _p_ := releasep() // 交出 P。 _p_.status = _Pgcstop sched.stopwait-- if sched.stopwait == 0 { // 最后一个让 stopTheWorldWithSema 里的 wait for 终止。 notewakeup(&sched.stopnote) } stopm() }
后台监控 sysmon 同样会被休眠(notesleep)。
// proc.go func sysmon() { for { usleep(delay) now := nanotime() next, _ := timeSleepUntil() if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs)) { if atomic.Load(&sched.gcwaiting) != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs) { if next > now { atomic.Store(&sched.sysmonwait, 1) notetsleep(&sched.sysmonnote, sleep) ... atomic.Store(&sched.sysmonwait, 0) noteclear(&sched.sysmonnote) } } } } }
StartTheWorld
让 MP 恢复执行。
// proc.go func startTheWorldWithSema(emitTraceEvent bool) int64 { lock(&sched.lock) // 重新设置 P 数量。 procs := gomaxprocs if newprocs != 0 { procs = newprocs newprocs = 0 } p1 := procresize(procs) // 返回有任务的 P 链表。 // 解除状态。 sched.gcwaiting = 0 // 唤醒 sysmon。 if sched.sysmonwait != 0 { sched.sysmonwait = 0 notewakeup(&sched.sysmonnote) } unlock(&sched.lock) // 唤醒有任务的 P。 for p1 != nil { p := p1 p1 = p1.link.ptr() // 绑定 M,继续执行。 if p.m != 0 { mp := p.m.ptr() p.m = 0 mp.nextp.set(p) notewakeup(&mp.park) } else { // Start M to run P. Do not start another M below. newm(nil, p, -1) } } startTime := nanotime() // 唤醒 idle P(即便没有任务)检查新任务。 if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 { wakep() } return startTime }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论