上卷 程序设计
中卷 标准库
- 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.5.5 终止线程
创建系统线程时,其执行函数为 mstart。
正常情况下,会进入调度循环,mexit 不会执行。
// proc.go func mstart() { mstart1() mexit(osStack) }
执行 mstart 时,线程在 g0 栈。
函数 mstart1 将 mstart PC、SP 保存到 g0.sched 里。
随后任何在 g0 栈执行的 mcall、systemstack,都不会修改 g0.sched。
如此,就保持了 mstart 做为 g0 初始栈帧模式。
func mstart1() { // Record the caller for use as the top of stack in mcall and // for terminating the thread. // We're never coming back to mstart1 after we call schedule, // so other calls can reuse the current frame. save(getcallerpc(), getcallersp()) schedule() }
func save(pc, sp uintptr) { _g_ := getg() _g_.sched.pc = pc _g_.sched.sp = sp _g_.sched.lr = 0 _g_.sched.ret = 0 _g_.sched.g = guintptr(unsafe.Pointer(_g_)) }
调度执行函数 execute 通过 gogo(G.sched)
切换执行用户函数。结束后,调用 goexit0 继续调度循环。
如果出错,goexit0 执行 gogo(g0.sched)
。如此,gogo 就跳转(jmp g0.pc)回 mstart,执行 mexit 终止线程。
func goexit1() { mcall(goexit0) // G.fn 在 G.stack 执行,要用 mcall 切换回 g0。 }
// goexit continuation on g0. func goexit0(gp *g) { locked := gp.lockedm != 0 if locked { // The goroutine may have locked this thread because // it put it in an unusual kernel state. Kill it // rather than returning it to the thread pool. // Return to mstart, which will release the P and exit // the thread. if GOOS != "plan9" { // See golang.org/issue/22227. gogo(&_g_.m.g0.sched) } } schedule() }
终止线程,其对应 M 从 allm 移除,加入 sched.freem 链表。
在 allocm 里,会释放所有 sched.freem g0 栈内存。
某些操作系统,g0 栈由系统提供,所以只从 allm 移除即可,无需加入 freem 链表。
In case of cgo or Solaris or Darwin, pthread_create will make us a stack.
Windows and Plan 9 will layout sched stack on OS stack.
// mexit tears down and exits the current thread. // // Don't call this directly to exit the thread, since it must run at // the top of the thread stack. Instead, use gogo(&_g_.m.g0.sched) to // unwind the stack to the point that exits the thread. func mexit(osStack bool) { // Remove m from allm. found: // Release the P. if osStack { // Return from mstart and let the system thread // library free the g0 stack and terminate the thread. return } // mstart is the thread's entry point, so there's nothing to // return to. Exit the thread directly. exitThread will clear // m.freeWait when it's done with the stack and the m can be // reaped. exitThread(&m.freeWait) }
结论
正常情况下,M 不会退出,stopm 让其进入休眠队列。
当前只有 UnlockOSThread 出错,才会导致终止。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论