栈的魔法:从栈切换的角度理解进程和协程

173 阅读2分钟

执行单元是指 CPU 调度和分派的基本单位,它是一个 CPU 能正常运行的基本单元。常见的执行单元有进程,线程和协程三种。

进程有自己独立的内存空间和页表,以及文件表等等各种私有资源。

同一个进程中的线程则共享该进程的内存空间,文件表,文件描述符等资源,它与同一个进程的其他线程共享资源分配。除了共享的资源,每个线程也有自己的私有空间,这就是线程的栈。线程在执行函数调用的时候,会在自己的线程栈里创建函数栈帧。

协程是比线程更轻量的执行单元。进程和线程的调度是由操作系统负责的,而协程则是由执行单元相互协商进行调度的,所以它的切换发生在用户态。只有前一个协程主动地执行 yield 函数,让出 CPU 的使用权,下一个协程才能得到调度。

协程主要有三个特点:

  • 占用的资源更少 ;
  • 所有的切换和调度都发生在用户态。
  • 它的调度是协商式的,而不是抢占式的。

fork 是一个系统调用,用于创建进程,如果其返回值为 0,则代表当前进程是子进程,如果其返回值不为 0,则代表当前进程是父进程,而这个返回值就是子进程的进程 ID。

fork 方法本质上在系统里创建了两个栈,这两个栈一个是父进程的,一个是子进程的。创建的时候,子进程完全“继承”了父进程的所有数据,包括栈上的数据。父子进程栈的情况如图 所示:

image.png

只要有一个进程对栈进行修改,栈就会复制一份,然后父子进程各自持有一份。图中的黄色部分也是进程共用的,如果有一个进程修改它,也会复制一份副本,这种机制叫做写时复制。

栈切换的核心就是栈指针 rsp 寄存器的切换,只要我们想办法把 rsp 切换了就相当于换了执行单元的上下文环境。


此文章为7月Day5学习笔记,内容来源于极客时间《编程高手必学的内存知识》