进程切换vs线程切换

319 阅读4分钟
  1. 我们都知道线程是cpu调度的最小单位,可是怎么才是cpu调度呢。对于cpu而言,他的工作就是“取指执行”,从内存中取出指令并执行。指令就是我们编写的代码编译后的产物二进制指令序列。因此我们只需要告诉cpu我们的指令序列在内存什么位置就可以了。我们通过cs代码段寄存器告诉cpu指令序列在内存哪个位置,这个位置是代码段的起始位置,然后我们再通过ip指令指针寄存器告诉cpu指令相对于代码段位置的偏移量。通过这两个寄存器cs+ip的组合就知道从内存哪个位置来取出指令来了,指令长度固定,取出一条指令后ip自动改变指向下一条指令。

  2. 根据1的cpu执行流程,我们的cpu调度比如进程切换或者线程切换,只需更改代码段寄存器cs跟指令指针寄存器ip的值,就可以让cpu去执行我们想要切换到的进程/线程的指令序列就可以了。所以cpu的调度就是进程/线程的切换。因此从这个角度看进程线程并没有太大差别。

  3. 我们的指令放在内存中,我们的数据也放在内存中。假设我们双开同一个程序,这两个进程加载的是同一份程序,指令序列完全一样,那么如果有某条指令是对同一份内存地址进行操作,结果肯定会引起错误操作,这不是我们想要的结果。因此指令序列中出现的内存地址,我们一般称为逻辑地址或者虚拟地址,必须经过一种映射转换成物理地址。因此对于不同的进程,指令中的内存地址虽然是一样的,但是经过映射后映射到自己进程所拥有的物理内存空间中。这样每个进程都需要一个映射表,来处理指令中虚拟内存到物理内存的转换关系。这个映射表就是内存管理中的页表。

  4.  所以每个进程都有自己的内存映射表,而cr3寄存器就是用来存储此页表目录表在内存中的位置(页表/页目录表可以看一下内存分页的相关知识)。

  5. 所以cpu每次执行指令时候,如果遇到内存相关的就必须先把指令中虚拟内存地址,根据从映射表取出的映射关系,转换成物理内存地址。每次指令执行都要从内存中找到映射关系,而从内存中取数据相对比寄存器来说速度是太慢了,为了提高执行效率,我们又搞了一组寄存器来缓存常用的映射关系,我们将这组寄存器缓存的映射关系称为TLB(Translation Lookaside Buffer)、快表。

  6. 所以进程切换时候,我们需要先切换代码段寄存器cs+指令指针寄存器ip以及各种用来记录进程上下文的寄存器,这一步我们完成指令的切换,然后我们还需要刷新TLB内存映射关系的快表。也是在这一步进程切换跟线程切换有了根本区别,因为线程是隶属于进程的,没有自己的独立的内存空间,进程下的所有线程都共用一套进程中内存映射关系,我们在切换线程时候只需要切换一下指令相关以及上下文相关的寄存器就可以了。所以速度也比较快,比进程更轻量级。

    总结; 线程跟进程区别,在于线程没有自己独立的内存空间,共用进程的内存空间。因此线程的切换,只需要切换指令就可以了,内存相关的缓存比如TLB依然有效。