什么才是cpu的上下文切换呢?
我们都知道,Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉。
而在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设定好cpu寄存器和程序计数器。
cpu寄存器,是cpu内置的容量小,但是速度极快的内存,而程序计数器,则是用来存储cpu正在执行的指令位置,或者即将执行的下一条指令位置,他们都是cpu在运行任何任务前,必须依赖的环境,因此也被叫做cpu上下文。
而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。
根据任务的不同,CPU的上下文切换可以分为不同的场景,也就是进程上下文切换、线程上下文切换、中断上下文切换。
进程上下文切换
进程是由内核来管理和调度的,进程的切换只能发生在内核态。进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。
进程可以在这内核空间和用户空间运行,分别称为进程的用户态和进程的内核态。
从用户态到内核态的转变需要通过系统调用来完成,需要进行CPU上下文切换,保存用户态的CPU上下文,加载内核态的CPU上下文,结束后相反,其中发生了两次CPU上下文切换。这一切都在同一个进程中进行,会消耗系统资源,但并不是进程的CPU上下文切换。
进程的上下文切换比系统调用多一步,在保存当前进程的内核状态和CPU寄存器之前,需要先把该进程的虚拟内存和栈等保存下来,而加载了下一个进程的内核状态和CPU寄存器之后,还需要刷新下一个进程的虚拟内存和栈等。
进程上下文切换次数较多,很容易导致CPU将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,大大缩短了真正运行进程的时间。导致平均负载升高。
线程的上下文切换
线程和进程的区别,线程是调度的基本单位,进程时资源拥有的基本单位,怎么理解呢?所谓内核中的任务调度,实际上调度的对象是线程,而进程时给线程提供虚拟内存、全局变量等资源的。
你也可以这样理解:
当进程只有一个线程时,可以认为进程就等于线程;
当进程拥有多个线程时,这些线程共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换时并不需要修改。
当线程也有自己的私有数据时,比如自己的栈和寄存器,上下文切换时也需要保存。
根据上面描述的,线程的上下文切换就存在两种情况:
1.前后切换的两个线程是属于同一个进程,两个线程的资源基本是共享的,切换上下文时共享的资源不需要动,只有当线程有私有数据时,切换这些不共享的数据即可;
2.前后切换的两个进程不属于同一个进程,跟切换进程的上下文时一样的。
切换同一进程的线程比切换进程消耗更少的系统资源,这就是多线程对比多进程的优势。