现代操作系统为了满足人们对于多道编程的需求,希望在计算机系统上能并发的同时运行多个程序,且彼此间互相不干扰。当一个程序受制于等待I/O完成等事件时,可以让出CPU给其它程序使用,令宝贵的CPU资源得到更充分的利用。
操作系统作为大总管需要协调管理各个程序对CPU资源的使用,为此抽象出了 进程(Process)的概念。 进程顾名思义就是进行中、执行中的程序。
物理层面上,一个CPU核心同一时间只能运行一个程序,或者说一个CPU核心某一时刻只能归属于一个特定进程。但逻辑层面上,操作系统可以进行进程调度,既可以为进程分配CPU资源,令其执行,也可以在发生等待外设I/O时,避免CPU空转而暂时挂起当前进程,令其它进程获得CPU。
进程能够随时在执行与挂起中切换,且每次恢复运行时都能够接着上次被打断挂起的地方接着执行。这就需要操作系统有能力保留进程在被挂起时的CPU寄存器上下文快照,当CPU中的寄存器被另外的进程给覆盖后,在恢复时能正确的还原之前被打断时的执行现场。 新老进程在CPU上交替时,新调度线程上下文的恢复和被调度线程上下文的保存行为被称作进程的上下文切换。
进程是一个独立的程序,与其它进程的内存空间是相互隔离的,也作为一个CPU调度的单元工作着,似乎很好的满足了需求。但有时候也存在一些场景,比如一个文件处理程序一方面需要监听并接受来自用户的输入,另一方面也要对用户的输入内容进行复杂,耗费大量时间的数据处理工作。人们希望在一个程序中既能处理耗时的复杂操作(例如定时存盘等大量的磁盘I/O),同时不能阻塞避免其无法及时的响应用户指令。
由于响应用户输入指令的程序与批处理程序都需要访问同样的内容,虽然操作系统提供了各式各样的进程间通信手段,但依然效率不高,为此,计算机科学家提出了 线程(Thread)的概念。
线程是属于进程的,同一进程下所有线程都共享进程拥有的同一片内存空间,没有额外的访问限制;但每个线程有着自己的执行流和调度状态,包括程序计数器在内的CPU寄存器上下文是线程间独立的。这样上述的需求就能通过在文件处理进程中开启两个线程分别提供用户服务和后台批处理服务来实现。通过操作系统合理的调度,既能实时的处理用户指令,又不耽误后台的批处理任务。
1. 在/kern/process/proc.[ch]中实现了进程/线程的创建、初始化、退出以及控制线程的运行状态等功能。
2. 在/kern/process/switch.S中实现了线程的上下文切换功能。
3. 在/kern/trap/trapentry.S中实现了forkrets,用于do_forks创建子线程后调用的返回处理。