在两个线程之间的上下文切换中究竟保存和恢复了什么
- 在同一个过程中
- 两个进程之间
这是一个相当复杂的问题,因为答案取决于许多事情:
至少需要保存正在使用的通用寄存器和程序计数器寄存器(假设大多数当前 CISC/RISC 样式通用 CPU 的通用设计)。
请注意,尝试只做与上下文切换相关的最小工作量是一些学术兴趣的话题
Linux 显然在公共领域有更多关于这方面的信息,尽管我的参考资料可能有点过时了。
有一个“task_struct”,其中包含大量与任务状态以及任务所针对的进程相关的字段。
其中之一是“thread_struct”</p>
/* 此任务的 CPU 特定状态 */
- struct thread_struct thread;
保存有关缓存 TLS 描述符、调试寄存器、
故障信息、浮点、虚拟 86 模式或 IO 权限的信息。
每个体系结构都定义了自己的 thread_struct,它标识了保存在交换机上的寄存器和其他值。
由于重命名寄存器的存在允许多个飞行指令(通过超标量或流水线相关的架构设计),这进一步复杂化。上下文切换的恢复阶段可能会依赖于 CPU 的流水线被恢复为初始空状态,这样尚未在流水线中退出的指令无效,因此可以忽略。这使得 CPU 的设计更加困难。
进程和线程的区别在于进程切换(在所有主流操作系统中总是意味着线程切换)将需要更新内存转换信息、IO相关信息和权限相关结构。
这些将主要是指向更丰富的数据结构的指针,因此与线程上下文切换相关的成本不会很大。
在同一进程的线程间进行上下文切换时,保存当前线程的所有非易失性通用寄存器,恢复新线程的所有非易失性通用寄存器;仅当当前线程执行被中断中断时,才需要保存易失性寄存器。线程使用的任何协处理器(例如浮点处理器)的寄存器也应保存和恢复如果切换是在 2 个进程的线程之间,除了正常的上下文切换所需的之外,内存和 IO 管理相关也应该进行改变;例如,进程所需的内存保护是使用页表和页目录表实现的,每个进程都有一个唯一的页目录表地址,当进程更改时必须更改该地址。
这取决于您使用的操作系统,但可以肯定的是,您必须保存所有寄存器的内容(包括指令计数器)并加载您要切换到的线程的寄存器。
关于在同一进程上的两个线程之间切换,我想到的唯一区别是您不会丢失 L1 和 MMU 缓存的内容。
我不确定,但如果我没记错的话,工作记忆集也会被切换。