cpu在执行每一个任务之前,都需要知道任务从哪里加载、从哪里开始运行。也就是需要系统事先设置好 CPU寄存器 和 程序计数器 ,它们都是cpu运行之前必须依赖的环境,也叫 cpu上下文。
名词解释:
- CPU寄存器:cpu寄存器是cpu内置的容量小,运行速度极快的内存
- 程序计数器:(Program Counter Register)是一块较小的内存空间,它可以看做是当前线程所执行的行号指示器,在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令、分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
CPU上下文切换就是把前一个CPU上下文(CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新的cpu任务。
cpu的上下文切换根据根据任务的不同可以分为下面几种不同的场景。
- 进程上下文切换
- 线程上下文切换
- 中断上下文切换
进程上下文切换
Linux按照特权等级,将进程的运行空间分为内核空间和用户空间;
- 内核空间:具有最高权限,可以访问所有资源
- 用户空间:只能访问受限资源,不能直接访问内存等硬件资源,必须通过系统调用陷入到内核中才能访问这些特权资源。
也就是说,进程既可以在用户空间运行,又可以在内核空间运行,进程在用户空间运行时,被称为用户态,而陷入内核态的时候,称为进程的内核态。从用户态到内核态会发生系统调用,一次系统调用会发生两次的CPU上下文切换。
系统调用不会涉及虚拟内存等进程用户态的资源,也不会切换进程。
- 进程上下文切换是从一个进程切换到另外一个进行运行
- 系统调用一直在同一进程中执行
进程切换和系统调用的区别:
- 进程切换只发生在内核态
- 进程的上下文不仅包含了虚拟内存,栈,全局变量等用户资源,还包括了内核堆栈、寄存器等内核空间的状态。
什么时候会切换进程上下文?
- 进程在系统资源不满足的时候,会被挂起,有CPU调度其他任务执行
- 当某个进程的时间片耗尽的时候,进程被挂起,切换到其他进行执行
- 当进程通过sleep函数主动挂起,也会引起进程切换
- 当有优先级更高的进程运行时,为确保高优先级的进程先执行,当前进程会被挂起
- 当发生硬件中断的时候,CPU上的进程会被中断挂起,转而执行内核中的中断服务
线程上下文切换
线程与进程的区别:
- 线程是调度的基本单位
- 线程有自己私有的栈和寄存器,当发生CPU上下文切换是,这些数据也要保存
- 进程是拥有资源的基本单位
- 内核中的任务调度实际上调度的是线程,进程只是给线程提供了虚拟内存、全局变量等资源
线程上下文切换:
- 前后两个线程属于不同进程,因为资源不共享,所以切换过程通进程上下文切换
- 前后两个线程属于同一进程,因为线程是共享内存的,所以切换时只需要切换私有数据
中断上下文切换
- 为快速响应硬件事件,中断处理会打断进程的正常调度和执行,转而调度中断处理程序。中断上下文切换不涉及进程的用户态
- 中断处理不进程拥有更高的优先级,所以中断上下文切换并不会和进程上下文切换同时发生