- 什么是任务调度器?
任务调度器就是操作系统中用于把任务轮流调度上处理器运行的一个软件模块,他是操作系统的一部分。调度器在内核中维护一个任务表(也称为进程表、线程表或调度表),然后按照一定的算法,从任务表中选择一个任务,然后把该任务放到处理器上执行,当任务运行的时间片到期后,再从任务表中找另外一个任务放到处理器上执行。
- 任务调度器的重难点?
在多任务系统中,任务切换是软件完成的,切换工作本身要消耗 CPU,导致所有任务的总共执行时间反而更长了。
- 执行流是什么?
执行流是独立的,他的独立性体现在每个执行流都有自己的栈、一套自己的寄存器映像和内存资源,这是 Intel 处理器在硬件上规定的,其实这正是执行流的上下文环境。
任何代码块,无论大小都可以独立称为执行流,只要在他运行的时候,我们提起准备好他所依赖的上下文环境即可。
- 程序、进程、线程
程序是静态的、存储在文件系统上、尚未运行的指令代码,他是世纪运行时程序的映像
进程是指正在运行的程序,即运行中的程序,程序必须在获取运行所需要的各类资源后才能成为进程,资源包括进程所使用的栈,使用的寄存器等
对于处理器来说,进程是一种执行流集合,集合中至少包含一条执行流,执行流之间是互相独立的,但他们共享进程的所有资源,他们是处理器的执行单位,或者称为调度单位,他们就是线程
按照进程中线程数量划分,进程分为单线程进程和多线程进程两种
进程拥有整个地址空间,其中包括各种资源,而进程中的所有线程共享同一个地址空间。各个进程都拥有自己的虚拟地址空间,正常情况下他们彼此无法访问道对方的内部,因为进程之间的安全性是有操作系统的分页机制来保证的。
- 线程提速的原理
原理之一就是实现多个执行流的伪并行。进程采用多个执行流和其他进程抢处理器资源,这样就节省了单个进程的总执行时间。
原理之二是避免了阻塞整个进程,比如当进程因等待用户输入而暂时无法继续运行时,此时操作系统会把整个进程挂起。但如果有多个线程,便可需要挂起一个线程即可,其他线程依然可以上处理器运行。
- 进程的身份证 — PCB
操作系统为每个进程提供了一个 PCB(Process Control Block),即程序控制块。用它来记录与此进程相关的信息,包括:寄存器映像、栈、栈指针、pid、进程状态、优先级、时间片、页表、打开的文件描述符、父进程的 pid 等
- 寄存器映像,用于保存进程的“现场”。一般位于 PCB 的顶端。当进程被换下 CPU 后,当前进程所使用的这一套资源(寄存器内容)应该存在寄存器映像中。任务在此在系统中运行时,会恢复这些寄存器资源
- 进程状态,指明了进程被换下的原因,以及下次调度器是否能把他换上处理器运行
- 时间片,告知了进程应该运行多久,当时间片的值为 0 时,表示该进程此次的运行时间到期了
- 页表,代表进程的地址空间
- 栈,此栈是进程所使用的 0 特权级下内核栈,并不是 3 特权级下的用户栈
ABI 规则
ABI:Application Binary Interface,即应用程序二进制接口,ABI 规定的是更加底层的一套规则,属于编译方面的约定。比如参数如何传递,返回值如何存储,系统调用的实现方式,目标文件格式和数据类型等。C 编译器就是按照这套 ABI 规则来编译 C 程序的,倘若我们全是用 C 语言来写程序,那就不用考虑 ABI 规则,这些是编译器考虑的事。C 语言和汇编语言是用不同的编译器来编译的,C 语言代码要先被编译成汇编代码,此汇编代码便是按照 ABI 规则生成的。因此如果要手动写汇编函数,并且此函数要供 C 语言调用的话,必须按照 ABI 规则去写汇编才行
我们的切换线程上 CPU 的函数 switch_to 就是使用的汇编语言,因此我们需要在汇编代码中保存这 5 个寄存器(ebp、ebx、edi、esi、esp)。保存的位置就是在线程栈中
位于 Intel 386 硬件体系上的所有寄存器都具有全局性,因此在函数调用时,这些寄存器对主调函数和被调函数都可见。这 5 个寄存器 ebp、ebx、edi、esi 和 esp 归主调函数所用,其余的寄存器归被调函数所用。也就是说,不管被调函数中是否使用了这 5 个寄存器,在被调函数执行完后,这 5 个寄存器的值不该被改变。因此被调函数必须为主调函数保护好这 5 个寄存器的值,在被调函数运行完之后,这 5 个寄存器的值必须和运行前一样。它必须在自己的栈中存储这些寄存器的值。其中 esp 会由调用约定(cdecl、fastcall)来保证,这里不用保护 esp。