CPU运行上下文的切换

CPU上下文就是CPU中所有寄存器、计数器的快照,是CPU工作环境。当CPU要执行另一个进程的时候,需要将一些寄存器的数值修改为目标进程的相应值,这个过程叫做CPU上下文切换。

CPU上下文切换发生在这几个场景中:

  1. 特权模式切换(系统调用)
  2. 进程上下文切换
  3. 线程上下文切换
  4. 中断上下文切换

特权模式切换(系统调用)

在Linux中,CPU特权模式切换就是用户态和内核态的切换,用户态进程通过调用系统调用进入到内核态,这个过程中一些特殊的CPU指令会被执行,将CPU切换特权模式,CPU的上下文也随之切换,切入切回,一次系统调用伴随着两次上下文切换。

第一次切换:调用系统调用时候,保存用户态的状态,然后切换到内核态,加载内核态代码。

第二次切换:内核态的系统调用处理代码执行结束后,退出特权模式,加载之前保留的用户态状态。

系统调用的切换过程中一直都是一个进程,和进程与进程的切换不同,不涉及虚拟内存等用户态资源。

进程上下文切换

进程是内核管理调度的,切换过程在内核态进行。相比系统调用中的切换,进程切换时需要保留更多状态数据,例如虚拟内存、栈、全局变量,和内核堆栈、寄存器数值。

进程上下文切换时,先保留当前进程的状态,然后加载下一个进程的状态,每次切换需要几十纳秒到几微妙的时间,开销比较大。(硬件寄存器的缓存需要被重新刷新,也使执行效率受到影响,在多核的机器,进程还可能在不同CPU核心上移动)

进程上下文切换是不可避免的,通常情况下,进程的数量一定是远远超过CPU核心数的,进程不能独占CPU,需要接受内核的调度,每次调度都会触发进程切换。

引发内核重新调度的因素有:

  1. 正在运行的进程的当前时间片耗尽
  2. 系统资源不足(譬如内存),进程需要等待
  3. 进程通过sleep等函数,将自己挂起
  4. 出现了优先级更高的进程(内核需要设置为支持抢占)
  5. 发生硬件中断,被切换到中断服务程序(注意,软中断不会触发切换)

如果一个进程因为被频繁地切换上下文,导致效率不高,可以将进程绑定指定CPU核心上。

线程上下文切换

进程是资源拥有的基本单位,线程是调度的基本单位。一个进程对应至少一个线程,可以对应多个线程。

隶属于同一个继承的线程间进行上下文切换的开销相对较小,因为它们有一部分共用的数据,这些数据可以免除切换。

中断上下文切换

中断通常是硬件发出的,也可以用实现“软中断”,中断发生后,CPU通常需要停下当前的工作,优先处理中断实现,指定中断事件对应的指令。

中断只发生在内核态。

中断会打断其它进程的调度和执行,带来额外的开销,如果中断次数过多,会显著降低整体系统。

参考