终于理解了进程切换慢的真正原因。
上下文:运行的状态、环境
进程
操作系统对运行的应用程序的抽象,进程的运行空间分为用户态和内核态,执行内核相关操作时,要进入内核态。
程序是被动实体,而进程是主动实体。一次只有一个进程可以在一个处理器上运行。
进程内存空间的组成包括:
- 用户栈:保存进程需要使用的各种临时数据,自顶向下扩展
- 代码库:进程执行有时需要依赖共享的代码库,这些代码库被映射到用户栈下方的虚地址处,标记为只读。
- 用户堆:堆管理的是进程动态分配的内存。字下向上扩展。
- 数据与代码段:他们原本保存在进程需要执行的 二进制文件中,进程执行前,操作系统将他们载入虚拟地址中。数据段都是全局变量
- 内核部分:位于进程地址空间的最顶端,只有当进程进入内核态时,才能访问内核内存,内核部分也有代码段与数据段。
进程的上下包括哪些:
- 堆栈
- 寄存器
- 代码和数据
- 内存
进程的想关状态用进程标识符PID保存,包括进程状态、虚拟内存状态、打开的文件。
进程切换过程:将进程的上下文信息保存在其对应的PCB中,接着将要切换到的进程的PCB中的数据恢复出来,开始执行。
线程
为什么要有线程
- 创建进程开销大:创建独立的地址空间、载入数据和代码段、初始化堆
- 进程间数据共享和同步麻烦,只能通过共享虚拟内存页(粒度粗)或基于进程间通信(开销大)
线程是在进程内部的可独立执行的单元,线程之间有独立的寄存器、堆栈但是共享数据、代码段和堆
在创建过程中,线程不需要分配内存空间,而进程需要,所以线程创建比进程快。
线程分为两类:
- 用户态线程:由应用自己创建,内核不可见,更轻量、开销更小,功能受限
- 内核态线程:由内核创建,受操作系统调度器管理
用户态线程功能受限,因此与内核态相关的操作,需要内核态线程协助。然后操作系统会建立起两种线程之间的关系,常见的由一对多,一对一,多对多,对字前面的是内核态线程。linux采用一对一模型
线程切换
类似与进程,线程有线程控制块TCB,在一对一模型中,内核态线程用户态线程各自保存自己的TCB。
线程切换只涉及程序计数器、寄存器、堆栈的切换,线程切换的消耗主要是进出内核的消耗。
为什么线程切换比进程切换快
因为进程切换比线程切换多了页表的切换(操作系统为每个进程搞一张页表,可能一级也可能多级),而页表切换会导致TLB失效,TLB中的内容要全部重写,所以所以慢了,切换页表很快,就是个指针的问题,内存变动也不是原因。