go关键字运行一个函数会创建一个新的goroutine执行函数。编译器会把go语句转成对runtime.newproc()函数的调用,这个函数使用systemstack()函数切换到g0的栈上:
1)执行newproc1()函数,newproc1()函数先尝试从P的gFree的gList中获取空闲的g,如果获取不到则从全局的gFree中批量取一部分,返回一个g。如果都没有获取到,则调用malg()新创建一个goroutine,分配内存并初始化相关数据结构,把函数的起始地址赋值给新goroutine的startpc成员。
2)调用runqput()把新goroutine加入到运行队列,优先放到当前P的本地队列,因为不需要加锁。首先,通过CAS原子操作把新goroutine设置成下一个要执行的g,也就是当前P的runnext成员变量。之前的那个oldnext会被移动到队列的末尾。如果队列已满,则调用runqputslow()移动一半的g到全局队列。访问全局队列的过程需要加锁。
3)调用wakep()尝试唤醒空闲的P、M执行调度。
newproc1()函数流程:
1. 首先,如果P本地的gFree的gList不空,尝试从中获取空闲的g,如果获取不到则从全局的gFree中批量取一部分,返回一个g
2. 如果没从gfree列表中取到g,则使用malg()函数创建一个新的g,分配的初始栈空间大小为2K。之后初始化g的栈空间;g.startpc成员赋值成新goroutine要执行的函数;
3. 设置g的sched结构体,该gobuf类型的结构体包含SP、PC等goroutine调度的寄存器上下文信息;
4. 把新g的状态更新为_Grunnable;
goroutine的创建通过go关键字调用newproc函数实现,newproc在系统线程栈上执行逻辑,包括调用newproc1创建新goroutine并将其添加到调度队列。newproc1会尝试从gfree列表获取或创建g,分配栈空间,并初始化gobuf结构体,最后将goroutine状态设为_Grunnable准备运行。
842

被折叠的 条评论
为什么被折叠?



