一、进程概念
进程是执行中的程序,形成所有计算的基础。更完整的解释是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来表示。
二、进程状态
进程有五种状态,分别是:
新的:进程正在被创建
运行:指令正在被执行
等待:进程等待某个事件的发生(如I/O完成或收到信号)
就绪:进程等待分配处理器
终止:进程完成执行
这五种状态的变迁图如下:
三、线程
线程由线程ID、程序计数器、寄存器集合和栈组成。它与属于同一个进程的其他线程共享代码段、数据段和其他操作系统资源。
线程是CPU调度的基本单元,进程是系统资源分配的基本单元,一个进程中可能包含多个线程。
多线程编程具有响应度高、资源共享、经济和多处理器体系结构的利用四个优点。虽然我们用户进程中可以有很多线程可以执行,但实际上这些用户线程都是映射到内核线程上来执行的。用户线程和内核线程之间的映射关系模型包含有:
(1)多对一
(2)一对一
(3)多对多
线程库为程序员提供了创建和管理线程的API。主要有两种方法来实现线程库,一种是用户空间的本地函数库(非系统调用),一种是系统直接支持的内核级库(系统调用)。目前使用的主要有三种线程库,如下:
(1)POSIX Pthread:Linux下使用的API,有用户级也有内核级的库
(2)Win32:Windows下的内核级线程库
(3)Java:用户级的库,Java虚拟机通常调用宿主机上的线程库来实现,在windows上就是采用win32 API。
四、CPU调度
我们通常说的CPU调度是讲进程调度,实际上现在支持一个进程包含多线程的操作系统中CPU的调度对象都是针对的内核线程,不过调度算法是一样的。下面我们都用进程调度来说调度算法。每个进程的执行都是若干个CPU区间和I/O区间组成,I/O约束程序通常具有很短的CPU区间,CPU约束程序可能有少量的长CPU区间,了解进程的这种分布有助于选择合适的调度算法。
CPU的调度决策会发生在如下四种情况下:
(1)运行-->等待
(2)运行-->就绪
(3)等待-->就绪
(4)运行-->终止
对于(1)和(4)两种情况都是运行的进程要么是资源条件不足,要么是运行结束了,这个时候需要选择新的就绪队列的进程转入运行状态,因此只有调度,没有选择;对于(2)和(3)两种情况下则是有进程进入就绪状态,这时可以选择。当调度只能发生在(1)和(4)两种情况下时,调度方案称为非抢占调度(新的就绪进程的出现不影响正在运行的进程),否则称为抢占调度(新的就绪进程可能抢占了当前运行进程的CPU资源)。
为了比较不同的调度算法,产生了许多的调度准则,如下:
CPU使用率:需要使CPU尽量忙
吞吐量:一个时间单元内所完成进程的数量
周转时间:从进程提交到进程完成的时间段
等待时间:在就绪队列等待所花费时间之和
响应时间:从提交请求到产生第一相应的时间
好的调度算法都是使CPU使用率和吞吐量最大化,而使周转时间、等待时间和响应时间最小化。下面一一介绍具体的调度算法。
1、先来先服务(FCFS)
最简单的CPU调度算法,根据进程进入就绪队列的先后顺序调度进程执行。但是这种方法的平均等待时间通常较长。
2、最短作业优先调度(SJF)
将每个进程与下一个CPU区间段相关联,当CPU空闲时,他回赋给具有最短CPU区间的进程。如果两个进程具有相同CPU区间长度,可以使用FCFS来调度。这里的CPU区间长度是进程的下一个CPU区间长度,而不是进程的CPU区间总长度。此算法可证明是最佳的,其难点在于如何知道进程的下一个CPU区间的长度。近似的情况下只能通过预测来做。
3、优先级调度
每个进程都有一个优先级相关联,具有最高优先级的进程会被分配到CPU,具有相同优先级的进程根据FCFS顺序调度。实际上短作业优先就是优先级调度算法的一个特例。
优先级调度算法的一个主要问题是导致低优先级的进程产生无穷阻塞或饥饿(可以运行但是缺乏CPU),其解决问题之一就是老化,即以逐渐增加在系统中等待很长时间的进程的优先级。
4、时间片轮转法调度(RR)
为分时系统而设计,类似于FCFS,不过每个进程只分配不超过一个时间片的CPU,对就绪队列中的进程依次循环分配时间执行。
5、多级队列调度
将就绪队列中的进程根据进程的属性不同而永久分配到多个独立的队列中,每个队列都有自己的调度算法。同时队列中也有调度,通常采用固定优先级抢占调度。
6、多级反馈队列调度
跟多级队列调度相似,最大的不同是允许进程在队列之间移动。主要思想是根据不同CPU区间的特点以区分进程,如果进程使用过多CPU时间,那么它会被转移到更低优先级队列。
多级反馈队列调度是最通用的CPU调度算法但是因为要设置很多调度参数,因此也是最复杂的算法。
五、多处理器调度
如果有多个CPU,则负载分配成为可能,同时相应的调度问题也变得更为复杂。与单处理器的CPU调度一样没有最好的调度算法。在多处理器上的CPU调度通常有两种方法,如下:
非对称多处理:让一个处理器处理所有调度决定、I/O处理以及其他系统活动,其他的处理器只执行用户代码。这种方法更简单,因为只有一个处理器访问系统数据结构,减轻了数据共享的需要。
对称多处理(SMP):每个处理器自我调度,调度通过每个处理器检查共同就绪队列并选择一个进程来执行。现在的操作系统一般都支持这种方式。
由于CPU的调度,因此一个进程通常不会在处理器上一次性执行完,中间可能会让出CPU,对于对称多处理调度方法,则有可能进程从一个处理器迁移到另外一个处理器上执行,而进程相关的数据在原处理器的缓存中,这样会导致缓存无效和重建,其代价很高;因此绝大多数非对称系统都尽量使一个进程在同一个处理器上运行,这个被称为处理器亲和性。
通过提供多个物理处理器,SMP系统允许同时运行几个线程。还有一种是提供多个逻辑处理器而不是物理处理器来实现,这种方法称为对称多线程(SMT)。也叫超线程技术。SMT实际上就是在一个物理处理器上生成多个逻辑处理器,向操作系统呈现一个多逻辑处理器的视图,同时每个逻辑处理器都有它自己的架构状态,包括通用的目的和机器状态寄存器。但是这种技术是需要硬件提供支持,而不是软件,硬件应该提供每个逻辑处理器的架构状态的表示和中断处理方法。