并发程序设计

第六章 并发程序设计

知识要点

程序的顺序执行与并发执行。

进程互斥:临界区、临界资源、临界区管理的实现方法。

进程同步:采用同步机制(信号量)解决同步问题。

管程:概念、特性、结构、条件变量和实现。

通信机制分类和实现原理。

死锁:定义、引发原因、死锁必要条件、死锁处理方法。


顺序程序设计特点

程序执行的顺序性;程序环境的封闭性;执行结果的确定性(与执行速度无关);计算过程的可再现性。

进程的并发性

  • 从宏观上看,一个时间段中几个进程都在同一处理器上。
  • 从微观上看,任一时刻仅有一个进程在处理器上运行。

程序并发执行的特点

失去了程序的封闭性,程序执行的结果依赖于程序执行时的相对速度。

注:如果程序执行的结果是一个与是一个与时间无关的函数,则具有封闭性。

并发程序设计的特性

并行性;共享性;交往性(多个进程间存在制约)。

程序并行性的表示

1、有向图

2、并行语言:PASCAL语言

并发进程分类

1、无关的并发进程

判断无关进程的条件:Bernstein条件

2、交往的并发进程:一组并发进程共享某些变量。

进程互斥

1、定义:若干进程因相互争夺独占型资源时所产生的竞争制约关系。

2、同步与互斥的比较

同步

互斥

进程-进程(直接关系)

进程-资源-进程(间接关系)

时间次序上受到某种限制

竞争到某一物理资源时不允许进程工作

相互清楚对方的存在及作用,交换信息

不一定清楚其进程情况

往往指有几个进程共同完成一个任务

往往指多个任务多个进程间通讯制约

例:生产与消费之间,作者与读者之间

例:交通十字路口

临界区管理

1、定义:与共享变量有关的程序段叫“临界区”,共享变量代表的资源叫“临界资源”。

2、临界区调度原则

  • 互斥使用,有空让进
  • 忙则等待,有限等待
  • 择一而入,算法可行

3、实现临界区管理的硬件设施

  • 关中断:不适合多CPU,一个进程只能禁止本CPU的中断。
  • 硬件指令方法
    • 一条机器硬件指令完成读写两个操作,如TS指令和SWAP指令。
    • 缺点:其他想进入临界段的进程必须不断地检测布尔变量lock的值,造成处理机的浪费,即“忙等待”;由于随机从等待队列中选取进程,会出现饥饿现象。
    • 优点:适用于多处理器情况;可以被适用于多重临界段情况。

信号量与PV操作

信号量的物理意义:信号量S的出初值表示可用资源数,当S≤0时,表示已无资源可分配,其绝对值表示此时在等待队列中等待分配资源的进程数。

信号量的变化范围:设可用资源数为m,进程数为n,则 -(n-m) ≤ S ≤ m。

P(s):将信号量s减去1,若结果小于0,则调用P(s)的进程被置成等待信号量s的状态。

V(s):将信号量s加1,若结果小于等于0,则唤醒一个等待信号量s的进程。

生产者-消费者问题

1、一个生产者/消费者共享一个缓冲区。

semaphore empty;/*可以使用的空缓冲区数*/
semaphore full;/*缓冲区内可以使用的产品数*/
empty = 1;
full = 0;
cobegin
process producer
{
while(1){
生产产品;
P(empty);
往缓冲区放产品;
V(full);
}
}

process consumer
{
while(1){
P(full);
拿产品;
V(empty);
消费产品;
}
}

2、多个生产者-多个消费者共享多个缓冲区

资源:空的缓冲区数、满的缓冲区数、空仓头指针,产品链头指针。

semaphore empty; empty = k;/*可以使用的空缓冲区数*/
semaphore full; full = 0;/*缓冲区内可以使用的产品数*/
semaphore Mutex_P0; Mutex_P0 = 1;/*互斥信号量*/
semaphore Mutex_C0; Mutex_C0 = 1;/*互斥信号量*/
int in = 0;/*放入缓冲区的头指针*/
int out = 0;/*取出缓冲区的头指针*/
cobegin
process producer_i
{
while(1){
生产;
P(empty);
P(Mutex_P0);
放入产品;
in = (in + 1) % k;
V(Mutex_P0);
V(full);
}
}

process consumer_j
{
while(1){
P(full);
P(Mutex_C0);
取出产品;
out = (out + 1) % k;
V(Mutex_C0);
V(empty);
消费产品;
}
}
coend

苹果橘子问题

资源:苹果,橘子,空位。

int plate;
semaphore sp;/*盘子里可以放几个水果*/
semaphore sg1;/*盘子里有橘子*/
semaphore sg2;/*盘子里有苹果*/
sp = 1;/*盘子里允许放入一个水果*/
sg1 = 0;/*盘子里没有橘子*/
sg2 = 0;/*盘子里没有苹果*/
process father{
while(1){
L1:削一个苹果;
P(sp);
把苹果放入plate;
V(sg2);
}

}
process mother{
while(1){
L2:剥一个橘子;
P(sp);
把橘子放入plate;
V(sg1);
}
}

process son{
while(1){
L3:P(sg1);
从plate中取橘子;
V(sg);
吃橘子;
}
}

process daughter{
while(1){
L4:P(sg2);
从plate中取苹果;
V(sg);
吃苹果;
}
}

读者-写者问题

资源:阅读者计数器、BUF(缓冲区)。

阅读者计数器信号量的变化范围:[-(m-1),1]

BUF信号量的变化范围:[-n,1]

int readcount;
semaphore Mutex_ReadCount = 1;
semaphore Mutex_BUF = 1;
process reader_i()
{
while(1){
P(Mutex_ReadCount);/*阅读者计数器登记*/
readcount++;
if(readcount==1)/*第一个阅读者申请BUF*/
P(Mutex_BUF);
V(Mutex_ReadCount);
读文件;
P(Mutex_ReadCount);
readcount--;
if(readcount==0)/*最后一个阅读者释放BUF*/
V(Mutex_BUF);
V(Mutex_ReadCount);
}
}

process writer_i()
{
while(1){
P(Mutex_BUF);
写文件;
V(Mutex_BUF);
}
}

哲学家就餐问题

哲学家就餐问题避免死锁的办法:

  • 至多允许四个哲学家同时吃。
  • 奇数号先取左手边的叉子,偶数号先取右手边的叉子。
  • 每个哲学家取到手边的两把叉子才吃,否则一把叉子也不取。

semaphore fork[5];
for(int i = 0;i < 5;i++)
fork[i] = 1;
cobegin
process philosopher_i()
{
while(1){
思考;
P(fork[i]);
P(fork[(i+1)%5]);
吃饭;
V(fork[i]);
V(fork[(i+1)%5];
}
}
coend

睡眠理发师问题

问题描述:理发店有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。如果没有顾客,理发师便在理发椅上睡觉,一个顾客到来时,它必须叫醒理发师,如果理发师正在理发时又有顾客到来,则如果有空椅子可坐,就坐下来等待,否则就离开。

资源:理发师、顾客、修改顾客人数的互斥信号量。

int waiting = 0;
int CHAIRS = N;
semaphore customers,barbers,mutex;
customers = 0;barbers = 0;/*理发师在睡觉*/
mutex = 1;/*互斥信号量*/
cobegin
process barber()
{
while(1){
P(customers);/*有顾客吗?若无顾客,理发师睡眠*/
P(mutex)/*若有顾客,进入临界区*/
waiting--;
V(barbers);/*理发师准备为顾客理发*/
V(mutex);
理发;
}
}

process customer_i
{
P(mutex);/*进入临界区*/
if(waiting<CHAIRS){/*有空椅子吗?*/
waiting++;
V(customers);
V(mutex);/*退出临界区*/
P(barbers);
理发;
}
else 
V(mutex);/*人满了,离开*/
}
coend

管程

1、引入目的:进程在使用过程中对信号量的操作分散在各个进程中,不易控制。

2、进程具有动态性,管程只是一个资源管理模块,供进程调用。

3、进程可以在任意时刻调用管程中的过程,管程在任一时刻只能有一个活跃进程。

4、管程中的条件变量:wait(类似P操作)、signal操作(类似V操作)。

进程通信

1、定义:进程之间的信息交换。

2、进程通信方式:

  • 低级通信原语:交换信息量较少,如互斥、同步机制。
  • 高级通信原语:交换信息量较多,如直接通信、间接通信。

直接通信

间接通信

定义

一个进程直接发送消息给接收者进程

进程通过一个“信箱”来传递消息

发送消息

原语send(P,消息):把一个消息发送给进程P

原语send(A,信件):把一封信件(消息)传送到信箱A

接收消息

原语receive(Q,消息):从进程Q接收一个消息

原语receive(A,信件):从信箱A中接受一封信件(消息)

3、消息队列:将消息组织成消息队列,用链指针链接起来,头指针放在进程的PCB中。

死锁及产生

1、定义:系统中的一组进程,由于竞争系统资源或由于彼此通信而永远阻塞,称这些进程处于死锁状态。

2、产生原因

  • 进程竞争资源,而资源不足。(不可剥夺资源)
  • 进程推进顺序不合适。

设系统某类资源有m个,有n个进程,每个进程需要k个该资源,则当满足nk ≤ m + (n - 1)时,系统不会引起死锁。

3、产生死锁的必要条件

  • 互斥条件:一个资源依次只能被一个进程所使用。
  • 不可抢占条件
  • 部分分配条件:一个进程已占有分给它的资源,但仍要求其他资源。
  • 循环等待条件:环形请求链。

进程-资源分配图

1、Pi → Rj为请求边,表示进程Pi申请资源类Rj中的一个资源。Rj → Pi 为分配边,表示Rj类中的一个资源已被进程Pi占用。

2、死锁的条件:进程-资源分配图中有环路且永远等待。

  • 若每类资源只有一个,出现环路一定发生了死锁。

处理死锁的基本方法

1、死锁的预防:破坏死锁产生的必要条件

  • 破坏互斥条件:资源可同时访问。
  • 破坏不可抢占条件:采用剥夺式调度方法。
  • 破坏部分分配条件:预先静态分配法。
    • 在进程开始运行之前,一次分配给其所需的全部资源,若系统不能满足,则进程阻塞,直到系统满足其要求。
  • 破坏循环等待条件:有序资源使用法。
    • 进程对资源的请求必须严格按资源序号的递增次序申请,经常用的普通的资源低序号,贵重少用的高序号。

2、死锁的避免:在分配资源时判断是否会出现死锁,如不会死锁,则分配资源。

  • 单资源银行家算法
    • 计算所有客户离最大需求的距离。
    • 检查系统资源状况,获得可以被满足的客户。
    • 一般挑选距离最短的客户,假设满足该客户,则可以收回该客户所分配的所有资源。
    • 计算剩余客户离最大需求的距离。
    • 返回(2),如此反复下去。若所有投资最终都被收回,则该状态是安全的,最初的请求可以批准。
  • 多资源银行家算法

3、死锁的检测和恢复

  • 撤销进程并剥夺资源
  • 使用挂起和解除挂起机构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值