【程序员必备小知识-性能基础11】进程的上下文切换详解

2,163 阅读3分钟

引言

学习的目的是为了提高自己思考的质量,并不是直接学完习就能学会解决问题,而是通过学习优化解决问题的过程,更加了解问题的发生,科学的不留任何隐患的去解决问题,所以了解cpu的上下文情况是必要的,为排查cpu负载过高打基础。

我在前面Cpu的上下文切换中提到,cpu的上下文切换是由于系统的多任务导致的,那会由于任务总类的不同,造成进程的上下文切换程度也不同,因此,我们按照任务的种类将cpu的上下文切换分为:进程、线程上下文切换中断上下文切换,前两个比较好理解,中断是怎么回事呢?不要忘了我们的硬件会通过触发信号导致中断程序的调用,比如我们的硬件驱动程序。

cpu上下文切换

系统调用

我们的Linux操作系统将进程的运行空间分为内核空间和用户空间,用户空间访问硬件资源是受限的,只有内核态空间能访问所有资源,那我用户要是读写一些硬件资源怎么办呢?对不起,你无权直接访问,但你可以通过系统调用的方式进行状态切换。

image.png

从cpu的角度看是这样的,寄存器先把当前进程的命令位置记录下来,然后保存起来,接着把当前进程的命令位置替换成内核态的指令的新位置,然后跳转到内核态执行任务,当系统调用结束后,还要切换回用户态继续执行,一次系统调用的过程,cpu上下文切换一共发生了两次,但却是在同一个进程中执行的。

所以系统调用过程通常称为特权模式切换,而不是上下文切换

进程上下文切换

要了解进程上下文切换之前,要知道进程是由谁管理的,由内核,那进程的切换也就处于内核状态下,因此,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态,所以在保存当前进程的内核状态和 CPU 寄存器之前,需要先把该进程的虚拟内存、栈等保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。

image.png

进程上下文切换的切换时机

什么时候进行进程上下文切换呢?这就要从进程调度说起,Linux为每个CPU都维护了一个就绪队列,就是等待队列,将活跃的进程不管是正在运行或者等待运行的进程按照优先级和等待 CPU 的时间排序,然后选择优先级最高和等待CPU时间最长的进程来运行。

触发进程调度的场景

为了保证CPU被均匀使用,CPU时间被划分成一个个时间片,每个进程执行的时候,就领到一个沙漏,要是倒计时结束了,不管进程执没执行完,就切换到其它CPU的进程执行。

进程在系统资源不足(比如内存不足)时,进程也会被挂起,并由系统调度其他进程运行。

当进程通过睡眠函数 sleep这样的方法将自己主动挂起时,自然也会重新调度。

当有优先级更高的进程运行时,能保证高优先级进程的运行。

硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序