进程的前三个部分(进程的基本概念、进程控制、线程)请阅读 操做系统-4-进程管理(一)html
4、进程同步程序员
概念:进程同步的主要任务是使并发执行的各进程之间能有效的共享资源和相互合做,从而使程序的执行具备可再现性。
1 进程同步的基本概念算法
(1)进程之间的两种制约关系:间接制约关系:系统资源竞争,进程间彼此无关
直接制约关系:进程间合做,彼此相关
(2)资源竞争需解决的两个问题:死锁(Deadlock)问题、饥饿(Starvation)问题(既要解决饥饿问题,又要解决死锁问题。)数组
(3)进程互斥:概念:进程互斥指若干进程要使用同一共享资源时,任什么时候刻最多容许一个进程使用,其余进程必须等待,直到占有资源的进程释放该资源。
做用:进程互斥是解决进程间竞争关系(间接制约关系)的手段。服务器
(4)进程合做:概念:进程合做是指某些进程为完成同一任务须要分工协做。
做用:进程合做是解决进程间协做关系(直接制约关系)的手段。网络
(5)进程合做与进程互斥的区别:进程同步指两个以上进程基于某个条件来协调它们的活动。一个进程的执行依赖于协做进程的消息或信号,数据结构
当一个进程没有获得来自于协做进程的消息或信号时需等待,直到消息或信号到达才被唤醒。并发
进程互斥是一种特殊的进程同步关系,即依次使用互斥共享资源,是对进程使用资源次序上的一种协调。函数
(6)临界资源(Critical Resource/CR):一次仅容许一个进程访问的资源。如:进程P一、P2共享一台打印机,若让它们交替使用则获得的结果确定是不可理解的。
临界资源多是硬件,也多是软件:变量,数据,表格,队列等。
并发进程对临界资源的访问必须做某种限制,不然就可能出现与时间有关的错误,如:联网售票。工具
(7)临界区(Critical Section/CS): 临界段,在每一个程序中,访问临界资源的那段程序。
与同一变量有关的临界区分散在各进程的程序段中,而各进程的执行速度不可预知。
若是能保证进程在临界区执行时,不让另外一个进程进入临界区,即各进程对共享变量的访问是互斥的,就不会形成与时间有关的错误。
与时间有关的错误: 一飞机订票系统,两个终端,运行T一、T2进程
T1 : T2:
... ...
Read(x); Read(x);
if x>=1 then if x>=1 then
x:=x-1; x:=x-1;
write(x); write(x);
... ...
注意:临界区是对某一临界资源而言的,对于不一样临界资源的临界区,它们之间不存在互斥。
如程序段A、B有关于变量X的临界区,而C、D有关于变量Y的临界区,
那么,A、B之间须要互斥执行,C、D之间也要互斥执行,而A与C、B与D之间不用互斥执行。
临界区的调度原则:一次至多容许一个进程进入临界区内
一个进程不能无限地停留在临界区内
一个进程不能无限地等待进入临界区
(8)同步机制应遵循的规则:空闲让进、忙则等待、有限等待、让权等待
用软件方法解决进程互斥问题:(设两个进程Pi、Pj使用临界资源。)
算法一分析:该算法规定了进程必须轮流执行;若某进程不须要进入CS,而另外一进程要求连续进入CS,该算法不能解决;破坏了“空闲让进”的准则;
算法二分析:该算法解决了算法一“空闲让进”的问题;
该算法中,若多个进程同时要求进入CS时,都发现对方进程的标志为“假”,会同时进入CS,这样,破坏了“忙则等待”的准则;
算法三分析:该算法解决了算法二“忙则等待”的问题;
该算法中,若多个进程同时要求进入CS时,都将本身的标志设为“真”,这样,互相谦让,谁也不会进入CS。这样,破坏了“空闲让进”的准则;
算法四分析:知足空闲让进、忙则等待、有限等待、让权等待四个规则
生产者消费者问题:
问题分析:利用一个数组表示具备n个缓冲区的循环缓冲池;
用输入指针in指示下一个可投放产品的缓冲区,每当生产者进程生产并投放一个产品,输入指针加1 (in:=(in+1) mod n);
用指针out指示下一个可从中获取产品的缓冲区,每当消费者进程取出一个产品,输出指针加1 (out:=(out+1) mod n) ;
----------------------------------------------------------------------------------------------------------------
2 信号量机制
概念:1965年,由荷兰学者Dijkstra提出,P、V操做分别是荷兰语的test (Proberen) 和increment (Verhogen) 。
信号量机制是一种卓有成效的进程同步机制。经历整型信号量、记录型信号量,发展为“信号量集”机制。
P、V操做是原语。
信号量的值除初始化外,只能由P、V原语修改。(wait、signal)
型号量的分类:信号量按其用途分为:公用信号量、私有信号量
信号量按其取值分为:二元信号量、通常信号量
(1)整型信号量:定义为一个整型量,由两个标准原子操做wait(S)(P操做)和signal(S)(V操做)来访问。
P(S) 或 wait(S): while S≤0 do no-op;
S:=S-1;
V(S) 或 signal(S): S:=S+1;
整型信号量出现“忙等”现象。
P(S) 或 wait(S): S:=S-1; S>0:可用资源数量
if (S<0) block(); S<0:|S|表示等待使用资源的进程数量
V(S) 或 signal(S): S:=S+1;
if (S<=0) wakeup();
利用整型信号量实现互斥:
(2)记录型信号量:记录型信号量机制采起“让权等待”策略,即当进程不能申请到资源时,让出CPU使用权。避免了整型信号量出现的“忙等”现象。
记录型信号量须要一个用于表明资源数目的整型变量value,一个用于连接全部等待进程的进程链表queue。
数据结构定义以下: struct semaphore {
int value;
pointer_PCB queue;
};
信号量说明:struct semaphore s;
P操做:P(s){
s.value = s.value -1 ;
if (s.value < 0){
该进程状态置为等待状态
将该进程的PCB插入相应的等待队列末尾s.queue;
}
}
V操做:V(s){
s.value = s.value +1 ;
if (s.value <= 0){
唤醒相应等待队列s.queue中等待的一个进程
改变其状态为就绪状态,并将其插入就绪队列
}
}
进程对CR进行申请:begin
repeat
P(S);
CS;
V(S);
remainder;
until false;
end
(3)AND型信号量
AND信号量是针对进程间共享多个资源;
例如:两个进程A、B要求访问共享数据D、E。为D、E分别设置用于互斥的信号量Dmutex、Emutex,初值为1。
process A: process B:
wait(Dmutex); wait(Emutex);
wait(Emutex); wait(Dmutex);
此处出现死等现象
AND同步机制的基本思想是:将进程在整个运行过程当中须要的全部资源,一次性所有地分配给进程,待进程使用完后再一块儿释放。
只要尚有一个资源未分配给进程,其它全部可能为之分配的资源,也不分配。
实现时在wait操做中,增长一个“AND”条件,故称为AND同步,或同时wait操做(Swait)。
-------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------
(4)信号量集
进程对信号量Si的测试值为ti(表示信号量的判断条件,要求Si >= ti;即当资源数量低于ti时,便不予分配)
占用值为di(表示资源的申请量,即Si=Si-di)
对应的P、V原语格式为:
Swait(S1, t1, d1; ...; Sn, tn, dn);
Ssignal(S1, d1; ...; Sn, dn);
通常“信号量集”能够用于各类状况的资源分配和释放,几种特殊状况:
(1)Swait(S, d, d)表示每次申请d个资源,当少于d个时,便不分配
(2)Swait(S, 1, 1)表示记录型信号量或互斥信号量
(3)Swait(S, 1, 0)可做为一个可控开关(当S1时,容许多个进程进入特定区域;当S=0时,禁止任何进程进入该特定区域)
(4)通常“信号量集”未必成对使用。如:一块儿申请,但不一块儿释放!
5、经典的进程同步问题(等我后续单独写博客)
1 生产者/消费者问题
2 读者/写者问题
3 哲学家进餐问题
6、管程机制
引入管程机制的缘由:减小大量的同步操做分散在各个进程中。
解决的办法——引入管程:为每一个可共享资源设立一个专门的管程,来统一管理各进程对该资源的访问。
管程(Monitor)的定义:一个管程包含一个数据结构和能为并发进程所执行(在该数据结构上)的一组操做,这组操做能同步进程和改变管程中的数据。
管程的三个部分:局限于管程内使用的共享变量的定义
对局限于管程的数据初始化
对该数据结构进行操做的一组过程
管程的特色:(1)局部数据变量只能被管程的过程访问,任何外部过程都不能访问。
(2)一个进程经过调用管程的一个过程进入管程。
(3)任什么时候候,只能有一个进程在管程中执行,调用管程的任何其余进程都被挂起,以等待管程变成可用的。(由编译器控制一次只能有一个进程调用管程)
(4)为了保证共享变量的数据一致性,管程应互斥使用。
(5)管程一般是用于管理资源的,所以管程中有进程等待队列和相应的等待和唤醒操做。
(6)在管程入口有一个等待队列,称为入口等待队列。当一个已进入管程的进程等待时,就释放管程的互斥使用权;
当已进入管程的一个进程唤醒另外一个进程时,二者必须有一个退出或中止使用管程。
(7)在管程内部,因为执行唤醒操做,可能存在多个等待进程(等待使用管程),称为紧急等待队列,它的优先级高于入口等待队列。
描述:一个进程进入管程以前要先申请,通常由管程提供一个enter()过程;
离开时释放使用权,若是紧急等待队列不空,则唤醒第一个等待者,通常也由管程提供外部过程leave()。
管程内部有本身的等待机制。管程能够说明一种特殊的条件型变量:var c:condition;其实是一个指针,指向一个等待该条件的PCB队列。
条件变量其实是区分阻塞的缘由。
条件变量:管程利用wait原语让进程等待,等待的缘由可用条件变量condition区别。它们应置于wait和signal以前。
例如:var X:condition;X.signal表示从新启动一个被阻塞的进程,但若是没有被阻塞的进程,则X.signal不产生任何后果。
利用管程解决生产者-消费者问题(待我后续发布博客)
7、进程通讯
1 概念
(1)所谓进程通讯是指进程之间信息交换。
(2)P、V操做实现的是进程之间的低级通讯,因此P、V为低级通讯原语。它只能传递简单的信号,不能传递交换大量信息。
(3)若要在进程间传递大量信息能够用Send、 Receive原语(高级通讯原语)。
(4)信号量机制做为同步工具成效显著,但做为通讯工具,存在不足:
效率低。生产者一次只能放一个产品(消息)到缓冲区,消费者一次只能取一个产品(消息);
通讯对用户不透明。
用户用低级通讯工具不够方便,由于数据结构设置、传送、进程互斥、同步等都由程序员负责。
2 进程通讯类型
高级通讯:用户可直接利用OS提供的一组通讯命令高效传送大量数据。分为:
(1)共享存储器系统(Shared-Memory System) :进程间经过共享某些数据结构或共享存储区进行通讯。
基于共享数据结构的通讯方式:多个进程经过公用某些数据结构交换信息。如:生产者-消费者问题中的有界缓冲区。
该方式低效。因数据结构设置、同步等由程序员负责。
基于共享存储区的通讯方式:高级通讯,在存储器中划出一块共享存储区,进程在通讯前,向系统申请共享存储区中的一个分区,
并指定该分区的关键字,若系统已经给其它进程分配了这样的分区,则将该分区的描述符返回给申请者。
接着,申请者把得到的共享存储分区链接到本进程上,此后可读写该分区。
注:以上两种方式的同步互斥都要由进程本身负责。
(2)消息传递系统(Message Passing System):进程间的数据交换以格式化的消息为单位,程序员利用系统的通讯原语实现通讯。 如:网络中的报文。
操做系统隐藏了通讯的实现细节,简化了通讯程序编制的复杂性,于是获得普遍应用。
消息传递系统可分为:
直接通讯(也称为消息缓冲通讯):发送进程直接把消息发送给接收者,并将它挂在接收进程的消息缓冲队列上。接收进程从消息缓冲队列中取得消息。
间接通讯:发送进程将消息发送到某种中间实体中(信箱),接收进程从(信箱)中取得消息。也称信箱通讯。在网络中称为电子邮件系统。
两种通讯方式的主要区别:前者须要两进程都存在,后者不须要。
(3)管道(Pipe)通讯 (共享文件方式):管道是最初的UNIX IPC形式,它能传送大量数据,被普遍采用。
所谓管道,是指用于链接一个读进程和一个写进程的文件,称pipe文件。
向管道提供输入的进程(称写进程),以字符流的形式将大量数据送入管道,而接受管道输出的进程(读进程)可从管道中接收数据。
管道能够是单工的,也能够是双工的。
管道分类:无名管道只限于相同祖先的进程间使用,是单向的。好比:父进程与子进程之间,或同一父进程的两个子进程间。
有名管道可在任意两个进程间使用,有名文件,有函数建立,而且建立进程即便终止了,该管道仍存在,是单向的,半双工的。
管道与消息队列的区别:管道中的消息是无界的
管道是外存的,消息队列是内存的
管道机制必须提供如下三方面能力:
互斥:一个进程读/写管道时,另外一个读/写进程必须等待。
同步:写进程写入后,只有等到读进程读走数据后,才能再写;一样,读进程无数据读时,只有等到写进程写入后,被唤醒再读。
肯定对方是否存在:只有对方存在时才能通讯。
3 消息传递通讯的实现方法
消息通讯分为直接通讯和间接通讯。
直接通讯方式:通讯命令(原语):Send(Receiver,message);
Receive(Sender,message);
间接通讯方式(信箱方式):信箱的建立与撤消。建立者应给出信箱名、属性(公用、私用或共享)等
信箱中消息的发送与接收:Send(mailbox,message);
Receive(mailbox,message);
信箱的种类(3类)
私用信箱:用户进程为本身建立的信箱,是进程的一部分。只有本身有权读,其余进程只能向信箱发消息;可采用单向链路实现。
公用信箱:由操做系统建立,全部系统核准进程均可使用;采用双向通讯链路实现。
共享信箱:由某进程建立并指明可共享,则拥有者和共享者可以使用。
利用信箱通讯时,有四种关系:1:1 发送和接收进程之间创建专用链路;
N:1 即客户/服务器;
1:N 发送进程可用广播方式向多个接收者发消息;
N:N 创建一个公共信箱,多个进程都能向信箱中发消 息,也能从信箱中取消息;
信箱使用规则:若发送信件时信箱已满,则发送进程被置为“等信箱”状态,直到信箱有空时才被唤醒
若取信件时信箱中无信,则接收进程被置为“等信件”状态,直到有信件时才被唤醒
Send实现:send(MailBox,M):把信件M送到指定的信箱MailBox中
步骤:查找指定信箱MailBox ;
若信箱未满,则把信件M送入信箱且唤醒“等信件”者;
若信箱已满,置发送信件进程为“等信箱”状态;
Receive实现:receive(MailBox,X):从指定信箱MailBox中取出一封信,存放到指定的地址X中 步骤:查找指定信箱MailBox ; 若信箱中有信,则取出一封信存于X中且唤醒“等信箱”者; 若信箱中无信件,置接收信件进程“等信件”状态;