当前位置:文档之家› 操作系统第五章 并发性:互斥和同步

操作系统第五章 并发性:互斥和同步


e=e-1 s=s-1 n=n+1
n=n-1 e=e+1

生产者 producer: while (true) { /* 生产v*/ semWait(empty); semWait(s); b[in] = v; semSigal(s); semSigal(full); in++; }

消费者 consumer: while (true) { semWait(full); semWait(s); w = b[out]; semSigal(s); semSigal(empty); out++; /* 消费w */ }
需要一个特殊变量(整数型):称为信号量

荷兰 计算机科学家

1 提出“goto有害论”; 2 提出信号量和PV原语(1965); 3 解决了“哲学家聚餐”问题; 4 最短路径算法(SPF)和银行家算法的创造者; 5 第一个Algol 60编译器的设计者和实现者; 6 THE操作系统的设计者和开发者;
死锁

进程之间互有对方必需的资源而不释放 例:R1 P2,R2 P1

饥饿

两个进程轮流访问临界资源,其他进程被无限地拒 绝访问资源,处于饥饿状态

共享合作关系

进程间接知道彼此的存在 进程间通过共享某些资源(如:变量、文件)进行 合作,但不确切知道对方

多个进程可以同时读一个数据项,但是必须互斥写 操作
P2: …… ② L2: printf(n); ③ n=0; ……. Go to L2;

例:
n=5, 共享变量;
①②③:输出6,n=0 ②③①:输出5,n=1
②①③:输出5,n=0
×

OS必须能够跟踪不同的进程,依靠PCB OS必须为每个活跃的进程分配和释放各种资源

处理器时间


存储器


机器指令方法的特点

适用于在单处理器或共享内存的多处理器上的任何数目的进程 非常简单且易于证明
可用于支持多个临界区,可以用自己的变量定义

缺点

忙等待:进程等待进入临界区,仍会继续消耗CPU 时间 可能饥饿:当需要选择等待进程进入时,某些可能被无限拒绝 可能死锁:低优先级的进程占有高优先级的进程所需资源
否会被阻塞

当进程对一个信号量加1后,另一个进程会被唤醒, 两个进程继续并发运行

在向信号量发出信号后,不需要知道是否有另一
个进程正在等待,被解除阻塞的进程数量或者没
有或者是1
信号量的值:资源个数
因信号量阻塞的进程队列
申请分配资源
当前进程放入队列s.queue 阻塞此进程
释放资源
从s.queue中移除该进程P 把进程P插入到就绪队列

临界区:进程访问临界资源的那段程序代码;
互斥:当一个进程在临界区访问临界资源时,其他进程不能进
入临界区。 同步:合作的并发进程需要按先后次序执行



死锁:多个进程等待其他进程的资源,形成循环等待链;
饥饿:一个进程呈可执行状态,被调度器忽视而不能调度执行。

并发的困难

共享全局资源,引发数据安全问题

设一信号量s,初始值为1

缓冲区满,生产者不能再加数据;缓冲区空,消费 者不能再取数据
生产者/消费者问题的无限缓冲区:in 〉out

生产者 producer:

while (true) {
/* 生产数据*/
b[in] = v;
in++; }
消费者 consumer: while (true) { while (in <= out) /*do nothing */; w = b[out]; out++; /* consume item w */ }
处理机上,实现并行执行。

并发的相关问题

进程间的通信
资源共享与竞争
多个进程活动的同步

分配给进程的处理器时间

并发出现的环境

多应用程序:共享处理器时间
结构化应用程序:设计成一组并发进程
操作系统结构:上一点用于操作系统

临界资源:一次仅允许一个进程使用的共享资源; 如:打印机、变量、数组

semWait和semSignal必须成对出现

互斥时,位于同一进程,临界区的前后 同步时,交错出现于两个合作进程内

多个semWait的次序不能颠倒,否则可能导致死锁; 用于同步的semWait应出现在用于互斥的semWait 之前

多个semSignal的次序可以任意

在进程对信号量减1之前无法提前知道该信号量是

多个进程读写共享数据时,必须保持数据一致性

通信合作关系

进程直接知道对方的存在
进程间通过发送消息和接受消息来进行通信,
实现同步和协调各种活动;

传递消息时,进程间未共享资源,则不需互斥,
但可能会死锁或饥饿,通信成为临界资源

必须强制实施互斥:一次只允许一个进程进入临界区 一个在非临界区停止的进程不能干涉其他进程 有限等待:决不允许出现需要访问临界区的进程被无限

putchar(chout);


解决办法:控制访问该变量的代码

规定一次仅允许一个进程进入echo,并只在
echo运行结束后,才对另一个进程可用

如何实施?

竞争条件:发生在多个进程或者线程读写数据时, 最终结果依赖于多个进程的指令执行顺序
P1: …… ① L1: n++ ……. Go to L1;

P1优先级低,进入临界区中断;P2优先级高,抢占CPU,需要访问同一临界资
源,等待;P1 无法再次得到CPU ,资源无法释放,进入死锁。

解决并发进程问题基本原理:

两个或多个进程可以通过简单的信号进行合作,
一个进程可以被迫在某一位置停止,直到它接到
一个特定的信号


复杂的合作需求都可以通过适当的信号结构完成

问题:按照什么顺序从等待队列移出?

先进先出(FIFO):阻塞最久的进程最先从队
列释放

强信号量:采用FIFO 策略的信号量

保证不会导致饥饿

弱信号量:没有规定移出顺序的(略)

对每一个临界资
源设一个信号量
s表示,初始化 为1;

每个进程进入临 界区之前执行
semWait(s),退出
临界区之后执行 semSignal(s);

信号量为实施互斥和进程间合作提供了强大灵 活的工具,但存难点

semWait和semSignal操作可能分布在整个程序中, 很难看出整体效果

因此提出管程(Monitor),一个程序设计语言结 构,可以锁定任何对象,提供与信号量相同的功能,
更易于控制

使用信号的管程

定义:管程由一个或多个过程、一个初始化序列和 局部数据组成的软件模块
文件 I/O设备

OS必须保护每个进程的数据和物理资源 进程的功能和输出结果必须与执行速度无关
实现互斥和同步

竞争关系

进程间相互不知对方存在 竞争:CPU、设备、内存等 影响:进程的结果与其他进程无关;会影响状态; 可能引发的问题:互斥

死锁 饥饿

互斥产生的额外控制问题

OS难对资源进行最优化分配-----死锁
难以定位程序设计错误

一个简单例子
void echo() ---多道程序设计系统中的共享函数
{
chin = getchar(); 全局共享变量
chout = chin;
putchar(chout);
}
P1 ——chin=getchar() 中断 P2——chin= getchar()

缓冲区是有限的---循环存储器
(b)

生产者 producer: while (true) { /* 生产数据*/ semWait(empty); semWait(s); b[in] = v; semSigal(s); semSigal(full); in++; }

消费者 consumer: while (true) { semWait(full); semWait(s); w = b[out]; semSigal(s); semSigal(empty); out++; /* consume item w */ }
chout = chin;
putchar(chout); P1恢复 chout = chin; putchar(chout);
Process P1

Process P2

chin = getchar();

chin = getchar();
chout = chin;

chout = chin; putchar(chout);
阻塞在信 号量lock

对于同步,“一类资源”配一信号量s,初
始值为可用资源数量

如:s表示缓冲区的空闲状态;

问题描述

有一组生产者生产数据,放在缓冲区(同步)

设一信号量empty, 初始值为缓冲区大小

有一组消费者取数据,每次取一项(同步)

设一信号量full,初始值为0
相关主题