进程模型
进程的三种状态:
1. 运行态(在该时刻实际占用处理机)
2. 就绪态(可运行,因为其他进程正在运行而暂时地被挂起)
3. 阻塞态(除非某种外部事件发生,否则不能运行)
进程在运行态和就绪态之间的转换是由操作系统的进程调度程序引起的,进程甚至感知不到调度程序的存在。
进程的实现:
进程调度程序要保证进程在运行态和就绪态之间转化时的一致性,即进程由就绪态转换为运行态时就像从未中断过一样。为了实现进程模型,操作系统维护一张进程表,该表包含了进程的状态,程序计数器,栈指针,内存分配状况,打开文件状态等信息。
调度过程:
中断发生时,中断硬件将当前进程的程序计数器,程序状态字,寄存器压入当前堆栈,而后跳转到中断向量所指向的地址。中断服务程序填充进程表项,然后将中断硬件先前存入的信息删除,并将栈指针指向一个进程管理者使用的临时堆栈。然后,中断服务程序调用调度程序,选择一个进程执行。
(?为什么使用临时堆栈,而不使用先前进程的堆栈。首先,进程堆栈空间大小未知。再者,使用进程堆栈会留下调度信息从而是恶意程序有机可乘。)
线程:
进程中的所有线程共享同一个地址空间。当一个进程包含多个线程时,进程表中保存的个别域需要转移到线程表中,针对每个线程的信息包括程序计数器,寄存器值及状态。每个进程拥有各自的堆栈。进程用于把资源集中到一起,而线程则是CPU上被调度的执行实体。
线程的实现:
一.用户空间中实现
把线程包放在用户空间中,内核感知不到线程的存在。用户空间管理线程时,每个进程需要专用的线程表。线程由用户空间的运行时系统管理。
优点:线程切换速度快、不需要操作系统支持、可定制调度算法、良好的伸缩性
问题:
1.当某一线程陷入内核阻塞时,由于内核感知不到线程的存在,故会阻塞当前进程,导致所有线程停止。
解决方案:
① 使用非阻塞版本的系统调用,但需要操作系统的支持,失去了灵活性。
② 在可能阻塞的系统调用前,使用select系统调用,得知read系统调用是否会阻塞,若会阻塞就启动其他线程,并在下次取得控制权后在此检查阻塞状况。
2.页面失效问题。
3.如果一个线程运行,其他线程就不能运行,除非运行线程主动放弃CPU.(因为在用户空间,没有时钟中断,不可能轮转调度)。
注:运行时系统可以可申请一个时钟中断,但开销太大,且线程也可能需要时钟中断,这会扰乱运行时系统的时钟中断。
二.内核空间中实现
内核实现线程时,进程中没有线程表,而由内核记录所有线程表。内核线程表保存每个线程的寄存器,状态和其他信息。同时,内核维护传统的进程表,用于跟踪进程状态。
优点:不需要新的,非阻塞的系统调用,发生阻塞和页面失效时内核可运行其他线程。
问题:系统调用代价太大,线程创建和销毁代价太大(可回收线程解决此问题)。