进程是资源分配和独立运行的基本单位
2.1 前驱图和程序执行
2.1.1 前驱图
前趋图:有向无循环图(DAG),用于描述进程之间执行的先后顺序
前趋图中的每个结点:可以表示一条语句、一个程序段或一个进程
结点间的有向边:表示两个结点之间存在的偏序关系或前趋关系“→ ”
2.1.2 程序顺序执行
程序顺序执行:必须按照某种先后次序逐个执行。
程序顺序执行时有如下特征:
顺序性:一个程序各个部分的执行,严格地按照某种先后次序执行。
封闭性:程序在封闭的环境下运行,即程序运行时独占全部系统资源。
可再现性:只要程序执行时的环境和初始条件相同,当程序重复执行时,都将获得相同的结果。
程序顺序执行的特性为程序员检测和校正程序的错误带来很大方便。 2.1.3 程序的并发执行
程序的并发执行:指一组在逻辑上互相独立的程序或程序段在执行时间上客观上互相重叠,即一个程序或程序段的执行尚未结束,另一个程序(段)的执行已经开始的方式。 程序并发执行时的特征:
间断性(异步性):互斥、同步
失去封闭性:共享资源 → 失去封闭性
不可再现性:失去封闭性 → 失去可再现性
程序并发执行时的不可再现性是绝对不允许的;因此应采取措施使并发程序保持其可再现性:引入进程,对并发执行的程序加以描述和控制。
程序并发执行条件(Bernstein 条件):
2.2 进程的描述
进程的定义:
进程是程序的一次执行。
进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
进程是程序在一个数据集合上的运行过程,它是系统进行资源分配和调度的一个独立单位。
引入进程实体的概念后(程序段 + 数据段 + 进程控制块),进程可以定义为:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
为了描述和记录进程的运动变化过程,并使之能正确运行,每个进程都应配置一个进程控制块(PCB)。从结构上看,每个进程(进程实体)都是由程序段、相关数据段及进程控制块组成。
进程实际上是指进程实体。
创建、撤销进程实际上指创建、撤销进程实体的PCB。
PCB是进程存在的唯一标志。
进程的特征:
动态性:进程的实质是程序在处理机上的一次执行过程,因此是动态。动态性是进程的最基本的特征。同时动态性还表现在进程则是有生命期的,它因创建而产生,因调度而执行,因得不到资源而暂停,因撤消而消亡。
并发性:指多个进程实体同时存在于内存中,能在一段时间内同时运行。引入进程的目的就是为了使进程能并发执行,以提高资源利用率,所以并发性是进程的重要特征,也是 OS 的重要特征。
独立性:指进程是一个能独立运行的基本单位,也是系统进行资源分配和调度的独立单位。
异步性:指进程以各自独立的、不可预知的速度向前推进。
2.2.2 进程的基本状态及转换
进程的三种基本状态:
New 新建/创建:进程正在创建中的状态。
Ready就绪:进程已获得了除处理机以外的所有资源,等待分配处理机执行的等待状态。
Running运行/执行:当一个进程获得必要的资源并正在处理机上执行的状态。
Waiting等待/阻塞:正在执行的进程由于发生某事件而暂时无法执行下去,此时进程所处的状态。
Terminated 终止/撤消/退出:进程执行完毕,释放所占资源的状态。
进程状态的转换:
2.2.3 挂起操作和进程状态的转换
进程的挂起状态:在某些系统中,为了更好地管理和调度进程,引入了挂起状态。
挂起状态/静止状态:程序在运行期间,由于某种需要,往往要将进程暂停执行,使其静止下来,以满足其需要。这种静止状态就称为进程的挂起状态。
挂起状态使进程置于静止状态
一般情况下,挂起状态的进程将从内存移到外存
正在执行的进程暂停执行
就绪的进程暂不接受调度
阻塞的进程即使阻塞事件释放也不能继续执行
2.2.4 进程管理中的数据结构
PCB是操作系统为了管理和控制进程的运行,而为每一个进程定义的一个数据结构,它记录了系统管理进程所需的全部信息。
PCB常驻内存,存放在操作系统中专门开辟的PCB区内。
进程控制块PCB的作用:
作为独立运行基本单位的标志
系统根据PCB而感知进程的存在,PCB是进程存在的唯一标志。
系统创建一个新进程时,就为它建立了一个PCB;进程结束时又回收其PCB,进程于是也随之消亡。
能实现间断性运行方式
利用PCB保存处理机状态信息,保护和恢复CPU现场。
提供进程管理所需要的信息
根据PCB中的程序和数据的内存始址,找到程序和数据。
系统根据PCB了解进程所需的全部资源。
提供进程控制所需要的信息
OS要调度某进程执行时,从PCB中查现行状态及优先级。
实现与其它进程的同步和通信
进程控制块中的信息:
进程标志符
处理机状态(断点信息)
进程调度信息
进程控制信息
进程控制块PCB的组织方式:
线性方式:将系统中所有的PCB都组织在一张线性表中,将该表的首址存放在内存的一个专用区域中。
链接方式:把同一状态的PCB链接成一个队列,这样就形成了就绪队列、阻塞队列等。
索引方式:将同一状态的进程组织在一个索引表中,索引表的表项指向相应的 PCB,不同状态对应不同的索引表。
2.3 进程控制
2.3.1 操作系统内核
进程控制是进程管理中最基本的功能,即对系统中所有的进程实施有效的管理,其功能包括进程的创建、撤消、阻塞与唤醒等,这些功能一般是由操作系统的内核通过原语来完成。 操作系统内核的功能:
支撑功能
中断处理
中断:CPU 对系统中或系统外发生的某个事件作出的一种反应。如外部设 备完成数据传输、实时设备出现异常等。
引入中断的目的:中断机制是操作系统得以正常工作的最重要的手段(操作系统是由中断驱动的)
中断可以解决:主机与外设的并行工作问题;提高可靠性;实现实时控制;中断是实现多道程序的必要条件
中断的分类:
中断处理过程:保存现场->转到中断处理程序->恢复现场
时钟管理(时间片)
原语操作
原语(Primitive):由若干条指令组成的,用于完成一定功能的一个过程。它与一般过程的区别在于:它们是“原子操作(Atomic Operation)”。
原子操作:原子操作,是指一个操作中的所有动作要么全做,要么全不做。换言之,它是一个不可分割的基本单位,因此,在执行过程中不允许被中断。 原语在核心态下执行,常驻内存。 处理机的执行状态:
为防止OS及其关键数据(如PCB等)不被用户有意或无意破坏,通常将处理机的执行状态分为两种:
这两种状态由一位触发器标识,通常属于程序状态字的一部分,即由PSW中的一位标识。
处理机状态由用户态转为核心态的唯一途径是中断。
资源管理功能
进程管理
存储器管理
设备管理
2.3.2 进程的创建
进程的层次结构:
在每个进程的PCB中都设置家族关系的表项,以表明自己的父进程和所有的子进程。
子进程可继承父进程的所有资源。
子进程撤销时要把资源归还给父进程。
父进程撤销时也必须撤销所有子进程。
进程图:
一个进程可以创建若干个新进程,新创建的进程又可以创建子进程。
进程图:又称为进程树或进程家族树,是描述进程家族关系的一棵有向树。
引起进程创建的事件:
用户登录:为该终端用户创建一个进程
作业调度:为被调度的作业创建进程
提供服务:如要打印时建立打印进程
应用请求:由应用程序建立多个进程(并发)
进程的创建过程:
操作系统一旦发现了要求创建进程的事件后,便调用进程创建原语Create按以下过程创建新进程。
申请空白的PCB
为新进程分配其运行所需的资源(静态、动态)
初始化进程控制块(PCB)
将PCB插入就绪队列
返回一个进程标识号
2.3.3 进程的终止
导致进程终止的事件:
进程正常结束(Holt、Logoff等)
进程异常结束(越界、超时、非法指令、I/O故障等)
外界干预(操作员、OS、父进程)
进程的终止过程:
如果系统中发生了要求撤消进程的事件,OS 便调用撤消原语Kill去撤消进程。(Destroy 、Termination)
根据终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态。
若该进程处于执行状态,终止该进程的执行并置调度标志为真。
若该进程还有子孙进程,将其子孙进程也都予以终止。
将被终止进程所拥有的全部资源归还给其父进程或系统。
将被终止进程(PCB)从所在队列/链表中移出。
2.3.4 进程的阻塞与唤醒
导致进程阻塞和唤醒的事件:
向系统请求共享资源失败
等待某种操作的完成
新数据尚未到达
无新工作可做
进程阻塞过程:
当进程期待的事件尚未出现时,该进程调用阻塞原语Block(由执行状态转为阻塞状态)把自己阻塞起来。
进程从执行态到阻塞态是主动的。进程发现需要等待某一事件,主动向系统申请进入阻塞态。
进程唤醒过程:
处于阻塞状态的进程,当期待的事件出现时,由其它相关进程调用唤醒原语 Wakeup(由阻塞状态变为就绪状态)把阻塞的进程唤醒,使其进入就绪状态。
进程从阻塞态到就绪态是被动的。当系统(或其它进程)发现阻塞进程阻塞的条件已释放,向系统申请将该进程置为就绪态。
2.3.5 进程的挂起与激活
进程的挂起:
当引起进程挂起的事件发生时,系统就将利用挂起原语Suspend将指定进程挂起。( 三种基本状态均可能挂起)
挂起是由进程自己或其父进程调 Suspend 原语完成。
进程的激活:
当发生激活进程的事件时,系统就将利用激活原语Active将指定进程激活。
激活是由父进程或用户进程请求激活指定进程,系统利用Active原语将指定进程激活。
系统调用是内核提供的功能十分强大的一系列的函数,是应用程序和操作系统内核之间的功能接口。
Fork 系统调用:
被 fork 创建的新进程叫做子进程。
在子进程中返回0,在父进程中返回子进程的pid。
在父进程中要返回子进程的pid的原因是父进程通过这个返回的子进程ID 来跟踪子进程。
对子进程而言,只有一个父进程,故返回0。
父进程的ID可以通过getpid取得。
在调用fork()之后,父进程和子进程均在下一条语句上继续运行。
父、子进程的fork()返回值不同:
在子进程中返回时,pid为0;
在父进程中返回时,pid为所创建的子进程的标识。
子进程的数据和堆栈空间和父进程是独立的,而不是共享数据。
Exit 系统调用:
exit()系统调用是用来终止一个进程的。无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。
exit系统调用带有一个整数类型的参数status,可以利用这个参数传递进程结束时的状态。0表示正常结束。其他的数值表示出现了错误,进程非正常结束。
系统调用exit的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程(zombie),并不能将其完全销毁。
Wait系统调用:
进程一旦调用了wait,就立即阻塞自己,由 wait自动分析是否当前进程的某个子进程已经退出。
如果让它找到了一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回。
如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
参数status 用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。
如果成功,wait调用会返回被收集的僵尸子进程的进程ID。
如果当前进程没有僵尸子进程,wait调用就会失败,此时wait返回-1。
Waitpid系统调用:
options提供了一些额外的选项来控制waitpid。
如果不想使用选项,也可以把options设为 0。
如果使用了选项 WNOHANG 参数调用waitpid,即使没有子进程退出,也会立即返回,不会像wait那样永远等下去。
waitpid 的返回值共有3种情况
当正常返回的时候,waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1。
2.4 进程同步
2.4.1 进程同步的基本概念
进程同步是指对多个相关进程在执行次序上进行协调,它的目的是使系统中诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。
用来实现同步的机制称为同步机制。如:信号量机制;管程机制。
两种形式的制约关系:
直接制约关系(进程同步):为完成同一个任务的诸进程间,因需要协调它们的工作而相互等待、相互交换信息所产生的直接制约关系。
间接制约关系(进程互斥):进程共享独占型资源而必须互斥执行的间接制约关系。
临界资源(Critical Resource):是一次只允许一个进程使用的资源,如打印机、绘图机、变量、数据等。
进程之间采取互斥方式实现对临界资源的共享,从而实现并行程序的封闭性
引起不可再现性是因为对临界资源没有进行互斥访问。
在每个进程中,访问临界资源的那一段代码称为临界区(CriticalSection),简称CS区。
不加控制地访问共享变量会产生错误:对临界区需要进行保护(互斥访问)
为了保证临界资源的正确使用,可以把临界资源的访问过程分成以下几部分:
进入区:增加在临界区前面的一段代码,用于检查欲访问的临界资源此刻是否被访问。
临界区:进程访问临界资源的那段代码。
退出区:增加在临界区后面的一段代码,用于将临界资源的访问标志恢复为未被访问标志。
剩余区:进程中除了进入区、临界区及退出区之外的其余代码。
同步机制应遵循的规则:
空闲让进:当无进程处于临界区时,表明临界资源处于空闲状态,应允许一个请求进入临界区的进程立即进入自己的临界区,以有效地利用临界资源。
忙则等待:当已有进程进入临界区时,表明临界资源正在被访问,因而其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问。
有限等待:对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免陷入死等状态。
让权等待:当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入忙等。
解决临界区(互斥)问题的几类方法:
软件方法:用编程解决。
Dekker 算法
Peterson 算法
硬件方法:用硬件指令解决。
关中断指令:如果进程访问临界资源时 (执行临界区代码) 不被中断, 就以利用它来保证互斥地访问。方法: 使用关中断、开中断原语。过程:关中断->临界区->开中断->剩余区
TestAndSet指令:
SWAP 指令:
信号量及P-V操作
管程
2.4.3 信号量机制
信号量机制,也称为P、V操作。
信号量:用于表示资源数目或请求使用某一资源的进程个数的整型量。
信号量只能通过初始化和两个标准的原语(P,V操作)来访问。
初始化:指定一个整数值,表示空闲资源总数。
P操作也称为wait操作,V操作也称为signal操作。
信号量是比锁更高级的资源抽象方式。
注意:P、V操作应作为一个整体实施,不允许分割。
整型信号量
非负整数,用于表示资源数目。除了初始化外,只能通过两个原子操作wait和 signal(P,V)来访问。
主要问题:只要S≤0,wait操作就不断地测试(忙等),因而未做到“让权等待”。
记录型信号量
为了解决“让权等待”问题,需要引入阻塞队列,信号量值可以取负值——记录型信号量。
设置一个代表资源数目的整型变量value(资源信号量)。
设置一链表指针L用于链接所有等待的进程。
执行一次P(s)操作,意味着进程请求分配该类资源一个单位的资源。
执行一次V(s)操作意味着进程释放相应资源一个单位的资源。当值小于等于0 时,表明有进程被阻塞,此时有释放的资源,则唤醒一个阻塞进程。
在记录型信号量机制中:
S.value>0:表示系统中某类资源当前可用的数目。
S.value≤0: 表示该类资源已分配完。若有进程请求该类资源,则被阻塞,其绝对值表示该信号量链表中因申请该资源而被阻塞进程的数目。
P操作过程描述:
V操作过程描述:
AND信号量集
在有些应用场合,是一个进程需要先获得两个或更多的共享资源后方能执行,但这种情况可能发生死锁。为避免死锁,可以采用AND 型信号量。
AND 型信号量的基本思想:
将进程在整个运行过程中所需要的所有临界资源,一次性全部分配给进程,待进程使用完后再一起释放。
只要有一个资源未能分配给进程,其它所有可能分配的资源也不分配给该进程。从而可避免死锁发生。
AND型信号量集P原语为Swait(Simultaneous Wait),V原语为Ssignal(Simultaneous Signal)。
一般信号量集
一般信号量集是同时需要多种资源、每种占用的数目不同、且可分配资源还存在一个临界值时的信号量处理。
—般信号量集的基本思路就是在AND型信号量集的基础上扩充,在一次原语操作中完成所有的资源申请。
进程对信号量Si的测试值为ti(表示信号量的判断条件,要求当资源数量低于ti时,便不予分配),占用值为di(表示资源的申请量,即 Si =Si - di 和 Si = Si + di)。
一般信号集的特点
一次可分配多个某种临界资源,不需执行多次 P 操作。
每次分配前都测试该种资源数目是否大于测试值。
Si:可用资源数 ti:阈值 di:申请资源数
2.4.4 信号量的应用
利用信号量实现进程互斥
利用信号量实现进程同步(前趋关系)
利用信号量实现进程互斥:
为临界资源设置一互斥信号量mutex,初值为1,取值范围(-1,0,1)。
当mutex=1时,表示两个进程皆未进入需要互斥的临界区;
当mutex=0时,表示有一个进程进入临界区运行,另外一个必须等待,挂入阻塞队列;
当mutex=-1时,表示有一个进程正在临界区运行,另外一个进程因等待而阻塞在信号量队伍中,需要被当前已在临界区运行的进程退出时唤醒。
利用信号量实现进程同步(前趋关系):
信号量可用来描述程序或语句间的前趋关系。
wait、signal 操作小结:
wait、signal操作必须成对出现,有一个wait操作就一定有一个signal操作。
当为互斥操作时,它们同处于同一进程。
当为同步操作时,则不在同一进程中出现。
如果两个wait操作相邻,那么它们的顺序至关重要,而两个相邻的signal操作的顺序无关紧要。
一个同步wait操作与一个互斥 wait 操作在一起时,同步wait操作在互斥 wait 操作前。
优点:简单,而且表达能力强(用wait、signal操作可解决任何同步互斥问题)。
缺点:不够安全,P、V操作使用不当会出现死锁。
2.5 经典进程的同步问题
生产者—消费者问题
哲学家进餐问题
读者—写者问题
生产者—消费者问题:
它描述了一组生产者向一组消费者提供产品,它们共享一个有界缓冲池,生产者向其中投放产品,消费者从中取得产品。
设置两个资源信号量及一个互斥信号量:
资源信号量empty:说明空缓冲区的数目,其初值为有界缓冲池的大小n。
资源信号量full:说明满缓冲区的数目(即产品数目),其初值为0。full+ empty= n。
互斥信号量mutex: 说明该有界缓冲池是一个临界资源,必须互斥使用,其初值为 1。 “生产者—消费者”问题的同步算法描述:
semaphore full=0; /* 表示满缓冲区的数目 /
semaphore empty=n; / 表示空缓冲区的数目 /
semaphore mutex=1; / 表示对缓冲区进程操作的互斥信号量 */
生产者—消费者问题是一个同步问题
消费者想要取产品,有界缓冲区中至少有一个单元是满的。
生产者想要放产品,有界缓冲区中至少有一个是空的。
它是一个互斥问题:有界缓冲区是临界资源,因此各生产者进程和各消费者进程必须互斥执行。
互斥信号量的P,V操作在每一程序中必须成对出现。资源信号量(full,empty) 也必须成对出现,但可分别处于不同的程序中。
多个P操作顺序不能颠倒。先执行资源信号量的P操作,再执行互斥信号量的P操作,否则可能引起死锁。
哲学家进餐问题:
有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。
此算法可以保证不会有相邻的两位哲学家同时进餐。
若五位哲学家同时饥饿而各自拿起了左边的筷子,这使五个信号chopstick均为0,当他们试图去拿起右边的筷子时,都将因无筷子而无限期地等待下去,即可能会引起死锁。
哲学家进餐问题的改进解法:
方法一:至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。
方法二:仅当哲学家的左右手筷子都拿起时才允许进餐。
1:利用AND信号量机制解决哲学家进餐问题:
2:利用信号量的保护机制实现:通过互斥信号量mutex对eat()之前取左侧和右侧筷子的操作进行保护,可以防止死锁的出现。
方法三:规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。
读者—写者问题:
一个数据对象(数据文件或记录)可被多个进程共享。其中,reader进程要求读,writer进程要求写或修改。允许多个reader进程同时读共享数据,但不允许一个writer进程与其它的reader进程或writer进程同时访问,即writer进程必须与其它进程互斥访问共享对象。
第一类:读者优先:
当一个读者正在读数据时,另一个读者也需要读数据,应允许第二个读者进入,同理第三个及后续读者都应允许进入。
现在假设一个写者到来,由于写操作是排他的,所以它不能访问数据,需要阻塞等待。如果一直有新的读者陆续到来,写者的写操作将被严重推迟。
该方法称为“读者优先”,即一旦有读者正在读数据,只有当全部读者退出,才允许写者进入写数据。
设置一个共享变量和两个互斥信号量。
共享变量 Readcount:记录当前正在读数据集的读进程数目,初值为0。
读互斥信号量Rmutex:表示读进程互斥地访问共享变量Readcount,初值为1。
写互斥信号量Wmutex:表示写进程与其它进程(读、写)互斥地访问数据集,初值为1。
第二类:写者优先
写者优先:当共享数据区被读者占用时,后续紧邻到达的读者可以继续进入,若这时有一个写者到来并阻塞等待,则写者后续到来的读者全部阻塞等待。
即只要有一个写者申请写数据,则不再允许新的读者进程进入读数据。这样,写者只需等待先于它到达的读者完成其读数据的任务,而不用等待其后到达的读者。
2.6 进程通信
进程通信:进程间的信息交换。
2.6.1 进程通信的类型
高级进程通信机制:
共享存储器系统(Shared Memory System)
消息传递系统(Message Passing System)
直接通信方式:消息缓冲通信
间接通信方式:又称为信箱通信方式
管道(Pipe) 通信:又称为共享文件通信
客户机-服务器系统 (Client-Server System)
共享存储器系统
基于共享数据结构的通信方式
系统提供了一种共享数据结构,适用于少量通信。
低效,不透明(数据结构的设置以及对进程间同步的处理,都必须由程序员来处理)。
例如producer-consumer中的缓冲区
基于共享存储区的通信方式
系统提供共享存储区。
通信过程:
①向系统申请一个或多个分区。
②对获得的分区进行读写。
特点:高效,速度快。
消息传递系统:
直接通信方式:消息缓冲通信
原语:
send ( Receiver,message ) 如接收者阻塞,则唤醒。
receive ( Sender,message ) 无消息则阻塞。
间接通信方式:又称为信箱通信方式
原语:
Send(mailbox,message)
Receive(mailbox,message)
信息单位:消息(报文)
实现:一组通信命令(原语), 具有透明性
管道通信:
管道: 连接读进程和写进程间通信的共享文件。
功能: 大量的数据发收。
管道通信必须提供三方面的协调能力:
共确定对方是否存在。
互斥:互斥访问管道。
同步:写满或读空管道后,进程睡眠等待,直到其它进程唤醒。
客户机-服务器系统通信机制:
套接字
套接字(Socket)是对网络中进程之间进行双向通信的端点的抽象。
一个套接字就是网络中进程通信的一端。
套接字是一个通信标识类型的数据结构,包含许多选项,由操作系统内核管理。
套接字可以通过网络应用程序的编程接口API实现。 通常套接字包括两类:
基于文件型。通信进程运行于同一台机器中,套接字关联到一个特殊文件,通信双方通过读写这个文件进行通信,类似于管道。
基于网络型。通信双方运行于不同主机的网络环境下。
远程过程调用和远程方法调用
远程过程调用:(Remote Procedure Call,RPC) 是一个计算机通信协议。
允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无
需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那
么远程过程调用亦可称作远程方法调用。
2.7 线程的基本概念
线程的引入:
目的:减少并发执行时的时空开销。因为进程的创建、撤消、切换较费时空,它既是调度单位,又是资源拥有者。
线程是系统独立调度和分派的基本单位,基本上不拥有系统资源,只需要少量的资源(指令指针IP,寄存器,栈),但可以共享其所属进程所拥有的全部资源。
进程与线程的比较:
调度的基本单位、并发性、拥有资源、独立性、系统开销、支持多处理机系统
线程运行的三个状态:
执行状态:线程正获得处理机而运行
就绪状态:具备了除CPU外的所有资源
阻塞状态:线程处于暂停执行时的状态
挂起是进程级的概念:一个进程被挂起,它的所有线程也必被挂起
线程控制块TCB:标志线程存在的数据结构,其中包含对线程管理所需要的全部信息:
线程标识符
寄存器状态:程序计数器和堆栈指针中的内容
堆栈:保存局部变量和返回地址
运行状态:执行、就绪、阻塞
优先级
线程专有存储器:保存线程自己的局部变量
信号屏蔽
多线程中的进程:
拥有系统资源的基本单位。
可包括多个线程。
不再是一个可执行的实体。所谓进程处于执行状态,实际上是指该进程中的某线程正在执行。
把某个进程挂起时,该进程中的所有线程也都被挂起。
把某进程激活时,属于该进程的所有线程也都被激活。
2.8 线程的实现
不论是系统进程还是用户进程,不论是进程还是线程,都必须直接或间接得到OS内核的支持。
2.8.1 线程的实现方式:
内核支持线程KST:内核支持线程由操作系统直接支持,在内核空间中执行线程的创建、调度和管理。
用户级线程ULT:用户线程指不需要内核支持而在用户空间中实现的线程。内核并不知道用户级的线程,所有线程的创建和调度都是在用户空间内进行的,而无需内核的干预。
组合方式:ULT/KST 组合方式线程系统:内核支持多个内核支持线程的建立、调度和管理,同时允许用户应用程序建立、调度和管理用户级线程。
2.8.2 线程的实现:
内核支持线程的实现:直接利用系统调用进行线程控制。
用户级线程的实现
运行时系统
轻型进程(LWP)(内核控制线程)
2.8.3 线程的创建与终止
线程的创建
应用程序启动时通常只有一个线程(初始化线程),主要功能是利用系统调用创建新线程。
线程的终止
线程被中止后并不立即释放它所占有的资源。
已被终止但尚未释放资源的线程,仍可以被其它线程所调用,重新恢复运行。
3.1 处理机调度的层次和调度算法的目标
3.1.1 处理机调度的层次
一个作业从提交开始,往往要经历三级调度:高级调度、中级调度、低级调度。
高级调度(长程/作业/宏观调度)
从外存后备队列中选择作业进入内存就绪队列。
在批处理系统中,大多配有作业调度。
作业调度执行频率较低,时间尺度是分钟、小时或天。
中级调度(交换调度)
在内存和外存对换区之间按照给定的策略选择进程对换。
解决内存紧张问题,提高内存的利用率和系统吞吐量。
低级调度(短程/CPU/进程/微观调度)
任务是从就绪队列中选择一个进程来执行并由分派程序(Dispatcher)分配处理机。
是 OS 中最基本的调度。
时间尺度通常是毫秒级的,由于低级调度算法的频繁使用,要求在实现时做到高效。
常采用非抢占(非剥夺)方式和抢占(剥夺)方式两种。
3.1.2 处理机调度算法的目标
处理机调度算法的共同目标:
资源利用率
公平性
平衡性(CPU 型进程和 I/O 型进程)
策略强制执行(抢占)
批处理系统的目标:
平均周转时间短
周转时间:作业从提交 → 完成的时间
周转时间组成:
①驻外等待调度时间
②驻内等待调度时间
③执行时间
④阻塞时间
周转时间不具有区分实际运行时间长短的性质。
平均周转时间T:
平均周转时间可以衡量不同调度算法对相同作业流的调度性能。
带权周转时间:周转时间除以系统服务时间Ts(占CPU时间)
带权周转时间越小越好。
系统吞吐量高
处理机利用率高
分时系统的目标
响应时间快(对交互性作业)
键盘提交请求到首次反馈结果的时间
时间组成:
①输入传送时间
②处理时间
③响应传送时间
均衡性
实时系统的目标
截止时间的保证
可预测性
3.2 作业与作业调度(高级调度)
3.2.1 批处理系统中的作业
作业 (job):
作业是把命令、程序和数据按照预先确定的次序结合在一起,并提交给系统的一个组织单位。
或者:作业是用户交给系统的具有独立功能的任务。
作业:程序和数据 + 作业说明书
在批处理系统中,是以作业为基本单位从外存调入内存的。
作业步 (job step):
一个典型的作业可分成三个作业步:①“编译”作业步;②“连结装配”作业步;③“运行”作业步。
作业控制块JCB:
在多道批处理系统中通常有上百个作业,为了管理和调度作业,系统为每个作业设置了一个作业控制块(JCB),它记录该作业的有关信息。不同系统的 JCB的组成内容有所区别。
JCB是作业在系统中存在的唯一标志。作业进入系统时由系统为每个作业建立一个 JCB;当作业退出系统时,则它的 JCB 也一起被撤消。
作业运行的三个阶段和三种状态:
收容阶段:当用户完成作业的提交,作业存在于外存中,系统建立JCB。在它还未被调度去执行前,该作业处于后备状态。
运行阶段:作业被调度进入内存,并以进程的形式存在,其状态是执行状态。处于执行状态的作业可以有多个。处于执行状态的作业并不意味着一定在CPU上运行,是否运行依赖于进程控制。
完成阶段:当作业已经完成其指定的功能,便进入停止状态,系统回收已分配资源。
作业调度的主要任务:
接纳多少作业:即多道程序的“道”。太多则可能会影响系统的服务质量(如周转时间太长),太少又将导致系统资源利用率和吞吐量的下降。根据系统的规模和运行速度来确定,同时要求I/O型进程与CPU型进程中和调度。
接纳哪些作业:取决于采用何种调度算法(先来先服务、短作业优先等)
3.2.3 先来先服务(FCFS)和短作业优先(SJF)算法
先来先服务调度算法FCFS:按进程(作业)进入就绪(后备)队列的先后次序来分配处理机(为其创建进程)。
短作业优先调度算法(SJF):主要任务是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。
类似地,用于进程调度的是短进程优先调度算法(SPF)
短作业优先调度算法的优缺点:
优点
能有效降低作业的平均等待时间。
能有效缩短进程的平均周转时间。
提高了吞吐量。
缺点
对长作业不利。
没有考虑作业的紧迫程度。
作业执行时间、剩余时间仅为估计。
SJF算法虽然是优化的,但在CPU调度中很难实现。
3.2.4 优先级调度算法和高响应比优先调度算法
优先级调度算法
优先级调度算法(Priority-Scheduling Algorithm, PSA) 以作业的紧迫程度为优先级。
优先级的类型:
静态优先级
优先权在创建进程时确定,且在进程的整个运行期间保持不变。一般用整数表示,小表示优先级高。
动态优先级
动态优先级在进程的存在过程中不断发生变化。
动态优先级的变化取决于:进程的等待时间;进程的运行时间;进程使用资源的情况
高响应比优先调度算法
高响应比优先调度算法(Highest Response Ratio Next, HRRN) 既考虑了作业的等待时间,也考虑了作业的运行时间,是一种动态优先级调度算法。
周转时间:从提交到完成的时间间隔。
响应时间:在交互式系统中,从提交请求到产生首次响应的时间,而不是到产生输出结果所需的时间。
3.3 进程调度(低级调度)
3.3.1 进程调度的任务、机制和方式
进程调度任务:
保存处理机的现场信息
按某种算法选取进程
把处理器分配给进程
进程调度机制:①排队器②分派器③上下文切换器
进程调度方式:
非抢占方式:
一旦把处理机分配给某进程,就让它一直运行下去,直至该进程完成或阻塞时,才把处理机分配给其它进程。
优点:是实现简单、系统开销小。
缺点:但它不能用于分时系统和大多数实时系统。
抢占方式:
允许调度程序根据某种原则,将已分配给该进程的处理机,重新分配给另一进程。
“抢占”必须遵循的原则:①优先权原则 ②短进程优先原则 ③时间片原则
最短剩余时间调度算法(SRT)
最短剩余时间调度算法(Shortest Remaining Time First, SRT) 是针对SPF 增加了抢占机制的一种调度算法。
它总是选择预期剩余时间最短的进程。只要新进程就绪,且有更短的剩余时间,调度程序就可能抢占当前正在运行的进程。
平均周转时间和带权平均周转时间说明了SRT好于前面的任何一个算法(因为它具有抢占的特点)。
3.3.2 时间片轮转调度算法(Round Robin,RR)
时间片轮转调度算法:系统将所有就绪进程按FCFS的原则,排成一个队列依次调度,把CPU分配给队首进程,并令其执行一个时间片,通常为10-100ms。时间片用完后,系统的计时器发出时钟中断,该进程将被剥夺CPU并插入就绪队列末尾。
时间片轮转调度算法保证了就绪队列中的所有进程在给定的时间内,均能获得一个时间片来执行,即系统在给定的时间内,可以响应所有用户的请求。
时间片轮转调度算法的平均周转时间比SPF长,但响应时间要短一些。
一个较为可取的时间片大小是,略大于一次典型的交互所需要的时间,使大多数交互式进程能在一个时间片内完成,从而可以获得很小的响应时间。
(同一时刻,新进程先入队尾,上一时间片结束进程后入队尾)
3.3.3 优先级调度算法
优先级调度算法的类型:
非抢占式优先级调度算法:一旦把处理机分配给就绪队列中优先级最高的进程后,该进程便一直执行下去直至完成,或者因该进程发生某事件而放弃处理机时,系统方可将处理机重新分配给另一优先级最高的进程。
抢占式优先级调度算法:只要出现了另一个其优先级更高的进程,调度程序就将处理机分配给新到的优先级最高的进程。
3.3.4 多级队列调度算法
SJF、SRT 都需要知道进程的运行时间,有局限性。
如果没有关于各个进程相对长度的任何信息,则可以用已经执行的时间进行衡量。
多级队列调度算法(MQ-Multilevel Queue)
根据作业的性质或类型,把就绪队列划分成若干个独立的队列,每个作业固定地分属一个队列。
不同的队列可以采用不同的调度算法。
3.3.5 多级反馈队列调度算法(MFQ)
是时间片轮转算法和优先级调度算法的综合和发展,通过动态调整进程优先级和时间片大小,不必事先估计进程的执行时间。
多级反馈队列调度算法调度机制:
设置多个就绪队列,并为每个队列赋予不同的优先级。队列1的优先级最高,其余队列逐个降低。
每个队列中进程执行时间片的大小各不相同,进程所在队列的优先级越高,其相应的时间片就越短。
新进程进入系统时,先放入队列1的末尾,按FCFS等待调度。如能在该时间片内完成,便可准备撤离系统,反之由调度程序将其转入队列2的末尾,按FCFS再次等待调度,如此下去,最后进入队列n按RR算法调度执行。
仅当队列1为空时,才调度队列2中的进程运行。若一个队列中的进程正执行,此时有新进程进入高级队列,则新进程抢占运行,原进程转移至本队列队尾。
3.3.6 基于公平原则的调度算法
保证调度算法
保证处理机分配的公平性。如果n个进程同时运行,公平的情况下每进程应该获得处理机时间的1/n。
公平分享调度算法
针对用户而不是进程,使得每用户获得相同的处理机时间。
3.4 实时调度
3.4.1 实现实时调度的基本条件
提供必要的调度信息(就绪时间、开始截止时间和完成截止时间、处理时间、资源要求、优先级)
系统处理能力强:在实时系统中,若处理机的处理能力不够强,则有可能因处理机忙不过来而致使某些实时任务不能得到及时处理。
采用抢占式的调度机制
具有快速切换机制
单处理机:
m: 实时任务数目,ci: 每次处理时间,pi: 周期时间
例如:有6个硬实时任务,周期时间都是50ms,每次的处理时间为10ms,则系统是不可调度的。
多处理机:(N: 处理机数目)
3.4.2 实时调度算法的分类
按实时任务性质(即对时间约束的强弱程度)
硬实时调度:必须满足任务截止期要求,错过后果严重。
软实时调度算法:期望满足任务截止期要求,错过可容忍。
按调度方式
非抢占式调度算法
非抢占式轮转调度算法:用于工业生产的群控系统中。
非抢占式优先调度算法:用于有一定时间要求的实时控制系统之中。
抢占式调度算法 (按抢占发生的时间)
基于时钟中断抢占的优先权调度算法
立即抢占的优先权调度算法
3.4.3 最早截止时间优先算法
最早截止时间优先算法(EDF算法, Earliest Deadline First )
算法是根据任务的开始截止时间和完成截止时间来确定任务的优先级。
截止时间越早,其优先级越高。就绪队列中任务按其截止时间排列,队首任务先分配处理机。
非抢占式调度方式用于非周期实时任务
抢占式调度方式用于周期实时任务
非抢占式调度方式用于非周期实时任务:
抢占式调度方式用于周期实时任务:
3.4.4 最低松弛度优先算法
最低松弛度优先算法(LLF,Least Laxity First)
低松弛 = 高紧急
算法是根据任务紧急(或松弛)的程度,来确定任务的优先级。任务的紧急度越高,其优先级越高,并使之优先执行。
算法采用抢占调度方式,可用于调度具有完成截止时间的周期性实时任务。
3.4.5 优先级倒置
优先级倒置的形成:高优先级进程(或线程)被低优先级进程(或线程)延迟或阻塞。 例如:有三个完全独立的进程TaskA、TaskB和TaskC,TaskA的优先级最高,TaskB次之,TaskC最低。TaskA和TaskC共享同一个临界资源X。 高优先级进程TaskA因低优先进程TaskC被阻塞,又因为低优先进程TaskB的存在延长了被阻塞的时间。
优先级倒置的解决方法:
Priority Ceiling:进程TaskC在进入临界区后,TaskC所占用的处理机就不允许被抢占。这种情况下,TaskC具有最高优先级(Priority Ceiling)。
Priority Inheritancea:
当高优先级进程TaskA要进入临界区使用临界资源X时,如果已经有一个低优先级进程TaskC正在使用该资源,可以采用优先级继承(Priority Inheritance)的方法。
此时一方面TaskA被阻塞,另一方面由TaskC继承TaskA的优先级,并一直保持到TaskC退出临界区。
3.5 死锁概述
资源的类型:
可重用资源(永久性资源):可被多个进程多次使用,如所有硬件。只能分配给一个进程使用,不允许多个进程共享。
消耗性资源:是在进程运行期间,由进程动态的创建和消耗的。消耗性资源在进程运行期间是可以不断变化的,有时可能为0;最典型的可消耗资源是用于进程间通信的消息。
可抢占资源:可抢占资源指某进程在获得这类资源后,该资源可以再被其他进程或系统抢占。对于这类资源是不会引起死锁的。CPU 和内存均属于可抢占性资源。
不可抢占资源:一旦系统把某资源分配给该进程后,就不能将它强行收回,只能在进程用完后自行释放。打印机等属于不可抢占性资源。
3.5.2 计算机系统中的死锁
死锁产生的原因:
竞争不可抢占资源引起死锁
竞争可消耗资源引起死锁
进程间推进顺序不当引起死锁
3.5.3 死锁的定义、必要条件和处理方法
死锁的定义:死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态,这些永远在互相等待的进程称为死锁进程。
产生死锁的四个必要条件:
互斥条件
请求和保持条件
不可抢占条件
循环等待条件
处理死锁的方法:
预防死锁:通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来防止死锁的发生。
避免死锁:在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免死锁的发生。
检测死锁:允许系统在运行过程中发生死锁,但可设置检测机构及时检测死锁的发生,并采取适当措施加以清除。
解除死锁:当检测出死锁后,便采取适当措施将进程从死锁状态中解脱出来。
3.6 预防死锁
破坏“请求和保持“条件
第一种协议:全分配,全释放: 采用预先静态分配方法,即要求进程在运行之前一次性申请它所需要的全部资源,在它的资源未满足前,不把它投入运行。
第二种协议:允许一个进程只获得运行初期所需的资源后,便开始运行。摒弃保持条件:进程运行过程中必须释放已分配给自己的且已经用完的全部资源,然后才能再请求新的所需资源。
破坏“不可抢占“条件
破坏“循环等待“条件
3.7 避免死锁
在资源的动态分配过程中,采用某种策略防止系统进入不安全状态,从而避免发生死锁。 3.7.1 系统的安全状态
安全状态指在某一时刻,系统能按某种进程顺序(p1,p2,…,pn)来为每个进程Pi分配其资源,直到满足每个进程对资源的最大需求,使每个进程都可顺利地完成,则称此时的系统状态为安全状态,称序列(p1,p2,…,pn)为安全序列。若某一时刻系统中不存在这样一个安全序列,则称此时的系统状态为不安全状态。
避免死锁的实质:确保系统不进入不安全状态
3.7.2 银行家算法
银行家算法的实质:设法保证系统动态分配资源后不进入不安全状态,以避免可能产生的死锁。
银行家算法执行的前提条件:要求进程必须预先提出自己的最大资源请求数量,这一数量不能超过系统资源的总量,系统资源的总量是一定的。
银行家算法中的数据结构:假定系统中有 n 个进程(P1,P2,…,Pn),m 类资源(R1,R2,…,Rm),银行家算法中使用的数据结构如下:
银行家算法描述(资源分配算法):
银行家算法描述(安全性算法):
(1)T0时刻的安全性:
(2)P1请求资源 Request1(1,0,2)
(3)P4请求资源 Request4(3,3,0)
(4)P0请求资源 Request0(0,2,0)
3.8 死锁的检测与解除
一旦死锁发生,系统应能将其找到并加以消除,为此需提供死锁检测和解除死锁的手段。
检测死锁的基本思想:在操作系统中保存资源的请求和分配信息,利用某种算法对这些信息加以检查,以判断是否存在死锁。
资源分配图:
资源分配图又称进程-资源图,它是描述进程和资源间的申请和分配关系的一种有向图。
圆圈表示进程节点P,方框表示资源节点R,方框中的小黑点数表示资源数。
请求边:Pi → Rj
分配边:Pi ← Rj
重要结论:如果资源分配图中不存在环路,则系统中不存在死锁;反之,如果资源分配图中存在环路,则系统中可能存在死锁,也可能不存在死锁。
死锁定理:
资源分配图的化简方法:
寻找一个既不阻塞又不孤立的进程结点 Pi,若无则算法结束;
去除 Pi 的所有分配边和请求边,使 Pi 成为一个孤立结点;
转步骤(1)。
在进行一系列化简后,若能消去图中所有的边,使所有进程都成为孤立结点,则称该图是可完全简化的;反之,称该图是不可完全简化的。
孤立结点:没有请求边和分配边与之相连。
阻塞结点:有请求边但资源无法满足其要求。
死锁定理:出现死锁状态的充分条件是资源分配图不可完全简化。
死锁的检测:
死锁检测算法的思想:死锁检测算法的思想是基于资源分配图化简和死锁定理来检测死锁。
死锁检测的原因:系统没有采取任何预先限制死锁的措施。资源分配时不检查系统是否会进入不安全状态, 被请求的资源都被授予给进程。需要周期性检测是否出现死锁。
检测时机:
在每个资源请求时都进行(相当于死锁避免)。
定时检测。
系统资源利用率下降时检测死锁。
3.8.2 死锁的解除
资源剥夺法: 当发现死锁后,从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态。
撤消进程法: 采用强制手段从系统中撤消一个/一部分死锁进程,并剥夺这些进程的资源供其它死锁进程使用。
撤消全部死锁进程。
按照某种顺序逐个地撤消进程,直至有足够的资源可用,使死锁状态消除为止。
基于最小代价原则一次只终止一个进程直到取消死锁循环为止。
撤消进程选择原则:
已消耗 CPU 时间最少
到目前为止产生的输出量最少
预计剩余的时间最长
目前为止分配的资源总量最少
优先级最低