处理机管理可归结为对进程的管理。
在单道程序系统中,程序只能够顺序的执行,即两个程序只能等一个执行完再执行下一个。这样就使程序的执行具有三个特型:顺序性、封闭性和可再现性。而到了多道程序系统中,允许程序并发的执行(宏观并行,微观串行)。此时程序并发执行就具有了:间断性、失去封闭性和不可再现性。为了解决程序并发执行的问题,并且可以对并发执行的程序加以描述和控制,人们就引入了进程的概念。
进程是程序的一次执行,是资源分配和调度的基本单位。进程 = 程序 + 数据 + 程序控制块(Process Control Block,PCB)。
PCB是进程最重要的数据结构,是进程存在的唯一标识。PCB中记录了系统所需的,用于描述进程的当前情况一起管理进程运行的全部信息。OS通过PCB就能够很好的控制进程。PCB中的记录的内容大致为:进程标识符、处理机状态、进程调度信息、进程控制信息。
进程的管理下面几个方面:
就绪状态——进程所需要的资源都已经到位,只需要等待处理机调度
运行状态——进程获得处理机,正在执行
阻塞状态——进程等待某些事件的发生才能继续执行,所以不再占用处理机而转为阻塞状态
进程的三态图和五态图如下:
进程的控制主要包括创建进程、撤销进程以及进程的状态转换。进程控制一般有OS的内核通过原语来实现。
内核(Kernel):一些常驻内存,存在于紧靠硬件的软件层次中的模块的集合。例如中断处理程序、常用设备驱动程序及运行频率较高的模块(时钟管理、进程调度这些)。
内核一般都包含了支撑功能(中断处理、时钟管理和原语操作)以及资源管理功能(进程、存储器和设备的管理)。
原语——由若干条指令组成的,用于完成一定功能的一个过程。或者说是系统态下执行的某些具有特定功能的程序段。原语操作是一种“原子操作”,就是不可分的意思。即一个操作中的所有动作要么全做,要么全不做。
阻塞和唤醒的原语分别是 block 和 wakeup。挂机和激活的原语是 suspend 和 active 。
进程同步机制的主要任务,是对多个相关进程在执行次序上进行协调,是并发执行的进程能按一定的规则(或时序)共享系统资源,并能很好的相互合作,从而使程序的执行具有可再现性。
进程之间的制约:
临界区:进程中访问临界资源的代码。
进程必须互斥地进入自己的临界区,系统为此设置了专门的同步机构来协调。同步机制需要遵循十六字真言:空闲让进、忙则等待、有限等待、让权等待。
1965年Dijkstra提出信号量(Semaphores)机制是一种卓有成效的进程同步工具,这个机制有几种发展产物。我们通常使用记录型信号量。
记录型信号量只是在整形信号量的基础上增加了将进程阻塞和唤醒的操作,这样符合“让权等待”的规则。
信号量S是一个表示资源数目的东西,只有在wait(S)和signal(S)这两个原子操作中才能够修改,这就保护了信号量不被其它地方随意改变。这两个操作又称为PV操作。
P操作就相当于在访问资源之前,先对代表该资源的信号量进行判断,如果有就访问,没有的话该进程就被阻塞等待。
V操作就是在访问资源之后,释放一个资源,并唤醒一个等待该资源的进程。
信号量机制实现前驱图也经常考到,但很简单。对于前驱图中一个结点,有多少个箭头指向它,则在执行本身程序之前必须先进行多少次 P 操作来等待所有资源。有多少个箭头从它指出去,在本身程序执行后就要进行多少次 V 操作释放资源。
为临界资源设置一互斥信号量mutex,初始值为1。每个进程在进入临界区之前都要对该信号量进行P操作,判断mutex的值,如果为1则表示没有其它进程正在访问该资源,现在可以访问;如果为0则表示当前有进程在访问该资源必须等待。这就相当于用一个标识符给临界区上了锁,实现了互斥访问。
两个进程共享缓冲池,想象生产者和消费者的问题。设缓冲池具有的可用空间为n,要为该缓冲池设置3个信号量,一个是互斥访问信号量S,初始值为1。一个是S1,初始值为n,表示缓冲池可用空间数。另一个是S2,初始值为0,表示缓冲池中已满空间数(相当于已有产品数)。在这个条件下:
对于生产者进程,在将产品放入到缓冲池(访问)之前必须先对 S1 进行 P操作,判断 S1 的值,如果不为0,就对 S 执行 P操作,判断该缓冲区中是否有其它进程正在访问。如果为 0,则表示该缓冲区已满不能再放产品,生产者进程只能等待。只有这两个 P操作都通过了,生产者才能将产品放入缓冲池。然后对 S 进行 V操作,释放访问,再对 S2(是S2,不是S1,因为放了一个产品是要给S2加1)进行 V操作。
对于消费者进程,在从缓冲池拿出产品(访问)之前必须现对 S2 进行 P操作,判断 S2 的值,如果不为0,就对 S 执行 P操作。如果为0,则表示缓冲区为空(没有产品),消费者进程必须等待。只有这两个 P操作都通过,生产者才能拿到产品。然后对 S 进行 V操作,表示自己不再访问临界区了。再对 S1 进行V操作。
虽然信号量机制已经是一种方便又高效的进程同步机制,但每个访问临界区的进程必须自备PV操作,这就是大量同步操作分散在各个进程中,不利于系统的管理,也容易产生死锁。为了解决问题,又引进了一个新概念——管程。
系统中的资源都可以用数据结构抽象地描述其资源特性,而忽略它们的内部结构和实现细节。因此,可以利用共享数据结构抽象地表示共享资源,并且将对该共享数据结构实施特定的操作定义为一组过程。简单理解,这个过程就是我们所说的管程。
有了管程之后,进程对共享资源的访问,可以不用自备PV操作了。直接通过这一个过程就可以,这一个过程就包括了进程对资源的申请、请求和其它操作。而这个过程可以确保每次只让一个进程进入,实现了互斥。也达到了对共享资源的所有访问的统一管理。
仔细想想,管程其实包含了面向对象的思想,将数据和操作都封装起来,隐藏实现细节。任何管程以外的过程都不能访问到里面的数据。进程也只需要调用管程中的方法就可实现对资源的访问。
如果说进程的引入是为了解决程序并发执行的问题,那么线程的引入则是为了更好的提高程序并发执行的程度。
因为进程本身是占有资源的,在进行进程调度时有很大的时空开销。所以再将进程分为更小的不带资源(占据很少量资源)的线程,然后以线程作为为调度和分配的基本单位来较小时空开销,提高并发程度。
进程之间因为存在着互斥和同步的关系,所以进程之间肯定需要进行一定的信息交换。(没有沟通,怎么能懂别人想干什么呢,对吧)
前面提到了信号量机制其实就是一种低级通信,因为每次只能告知另一个进程一个信息。比如说放了一个产品,而不能说放很多产品了。
高级通信就是能够高效地传送大量数据,并且使用方便,对用户透明(系统隐藏了实现进程通信的具体细节)。
一个很关键的概念:在操作系统中,“透明” 一词指某种东西实际存在,但从某个角度看好像没有。就是对应用人员来说不可见(你只能按它说的做,但不能直接控制)。
高级通信包括:
三级调度的概念:
调度算法:先来先服务、时间片轮转法、优先级调度、多级反馈队列调度(具体算法思想就不再赘述)
死锁:一组进程中的每个进程都在等待着只能由改组进程才能引发的事件。
死锁必要条件:互斥条件、请求和保持条件(就是既占有资源,又请求新资源)、不可抢占条件,环路条件。
死锁预防:通过破环四个必要条件中的一个或几个。一次性分配法(破坏请求和保持条件)、有序资源分配法(破坏环路条件)
死锁避免:银行家算法,就是对每一次分配资源都要判断是否是安全状态,安全才分配,不安全则不分配,开销很大。
死锁检测:看图法
死锁解除:抢占资源、终止进程。