北京航空航天大学计算机学院-2020春操作系统课程
题目作者为北航计算机学院操作系统课程组,答案为博主原创。水平有限,无法保证作答正确性,如有错误敬请批评指正。部分作答源自百度谷歌等其他资料,如有侵权联系删除
1 三个进程 P1、P2、P3 互斥使用一个包含 N(N>0)个 单元的缓冲区。P1 每次用 produce() 生成一个正整数并用 put() 送入缓冲区某一个空单元中;P2 每次用 getodd() 从该缓冲区中取出一个奇数并用 countodd() 统计奇数个数;P3 每次用 geteven() 从该缓冲区中取出一个偶数并用 counteven() 统计偶数个数。请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义的信号量的含义。
缓冲区是三个进程的共享空间,对其访问需要信号量保护,设为 mutex,初值为 1
P1、P2共享缓冲区中的奇数,奇数的个数需要统计,用信号量 odd 表示,初值为 0;P1、P3共享缓冲区中的偶数,偶数的个数需要统计,用信号量 even 表示,初值为 0
缓冲区满时 P1 不能再送入整数,缓冲区的空位数需要统计,用信号量 empty 表示,初值为 N
三个进程操作缓冲区前后都进行 P(mutex) 和 V(mutex) 操作,mutex 对缓冲区加锁以保证不会冲突,缓冲区操作完后释放锁;P1 将整数送入缓冲区时进行 P(empty),消耗缓冲区的空位,以保证没有空位时不再送入整数,同时每次送入数根据奇偶执行 V(odd) 或 V(even) 之一的操作,增加奇数和偶数的数量;P2 每次获取奇数时进行 P(odd) ,随后进行 V(empty),P3 每次获取偶数时进行 P(even) ,随后进行 V(empty)。
Semaphore mutex = 1, odd = 0, even = 1, empty = N;
P1:
while(true) {
P(empty);
integer = produce();
P(mutex);
put();
V(mutex);
if (integer % 2 == 0)
V(even);
else
V(odd);
}
P2:
while(true) {
P(odd);
P(mutex);
gedodd();
V(mutex);
V(empty);
countodd();
}
P3:
while(true) {
P(even);
P(mutex);
gedeven();
V(mutex);
V(empty);
counteven();
}
2 一个野人部落从一个大锅中一起吃炖肉,这个大锅一次可以存放 M 人份的炖肉。当野人们想吃的时候,如果锅中不空,他们就自助着从大锅中吃肉。如果大锅空了,他们就叫醒厨师,等待厨师再做一锅肉。
野人线程未同步的代码如下:
while(true) {
getServingFromPot();
eat();
}
厨师线程未同步的代码如下:
while(true) {
putServingsInPot(M);
}
同步的要求是:当大锅空的时候,野人不能够调用 getServingFromPot();仅当大锅为空的时候,大厨才能够调用 putServingsInPot()。问题:请写出满足同步要求的野人线程和厨师线程的同步原语。
野人在没有食物的时候需要阻塞等待,厨师在有食物的时候需要阻塞等待,因此用两个信号量 isEmpty 和 haveFood 分别表示厨师阻塞等待和野人阻塞等待的条件,初始状态没有食物。使用普通类型变量 food 监控食物剩余量。havefood 信号量保证每次只有一个野人操作锅里的食物以及 food 变量,在一个野人进程获取一份食物后,其判定锅里是否还有食物,若还有食物则唤醒其他野人进程,若没有食物则唤醒厨师进程。
Semaphore isEmpty = 1, haveFood = 0;
int food = 0;
Savages:
while(true) {
P(haveFood);
getServingFromPot();
food--;
if (food == 0)
V(isEmpty);
else
V(haveFood);
eat();
}
Cook:
while(true) {
P(isEmpty);
putServingInPot(M);
food += M;
V(haveFood);
}
3 系统中有多个生产者进程和消费者进程,共享用一个可以存 1000 个产品的缓冲区(初始为空),当缓冲区为未满时,生产者进程可以放入一件其生产的产品,否则等待;当缓冲区为未空时,消费者进程可以取走一件产品,否则等待。要求一个消费者进程从缓冲区连续取出 10 件产品后,其他消费者进程才可以取产品,请用信号量 P, V 操作实现进程间的互斥和同步,要求写出完整的过程,并指出所用信号量的含义和初值。
题目规定一个消费者连续取出 10 件产品后才能改由其他消费者取产品,那么直接在生产者-消费者模型基础上让每个消费者连续取 10 次,而该消费者取 10 次期间别的消费者不能打扰,设定信号量 lock 来保护连续取产品的过程,而生产者不受 lock 信号量的约束。
Semaphore mutex = 1, empty = 1000, product = 0, lock = 1;
Consumer:
while(true) {
P(lock);
for (int i = 0; i < 10; i++) {
P(product);
P(mutex);
consume();
V(mutex);
V(empty);
}
V(lock);
}
Producer:
while(true) {
P(empty);
P(mutex);
produce();
V(mutex);
V(product);
}
1 读者写者问题的写者优先算法 : 1)共享读; 2)互斥写、读写互斥; 3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)。
Semaphore write_write = 1; // 保证写-写互斥
Semaphore read_write = 1; // 保证读-写互斥
Semaphore writers_mutex = 1; // 保证访问共享变量writers互斥
Semaphore readers_mutex = 1; // 保证访问共享变量readers互斥
Semaphore write_pendings = 1; // 保证写者优先于读者
int writers = 0, readers = 0; // 计数写者和读者的数量
Readers:
while(true) {
P(write_pending);
P(read_write);
P(readers_mutex);
readers++;
if (readers == 1)
P(write_write);
V(readers_mutex);
V(read_write);
V(write_pending);
read();
P(readers_mutex);
readers--;
if (readers == 0)
V(write_write);
V(readers_mutex);
}
Writers:
while(true) {
P(writers_mutex);
writers++;
if (writers == 1)
P(read_write);
V(writers_mutex);
P(write_write);
write();
V(write_write);
P(writers_mutex);
writers--;
if (writers == 0)
V(readBlock);
V(writers_mutex);
}
2 寿司店问题。假设一个寿司店有5 个座位,如果你到达的时候有一个空座位,你可以立刻就坐。但是如果你到达的时候5 个座位都是满的有人已经就坐,这就意味着这些人都是一起来吃饭的,那么你需要等待所有的人一起离开才能就坐。编写同步原语,实现这个场景的约束。
Semaphore mutex = 1; // 保证客人到达与离开时计算的互斥
Semaphore block = 0; // 用于等待队列
bool must_wait = False; // 为真表示寿司店已满需等待
int eating = 0; // 记录在寿司店就餐的线程数
int waiting = 0; // 记录在寿司店等待的线程数
while (true) {
P(mutex);
if(must_wait) {
waiting++;
V(mutex);
P(block);
} else {
eating++;
if (eating == 5)
must_wait = true;
else must_wait = false;
V(mutex);
}
sit_and_eat();
P(mutex);
eating--;
if (eating == 0) {
int n = min(5, waiting);
waiting -= n;
eating += n;
if (eating == 5)
must_wait = True;
else must_wait = False;
while(n--)
V(block);
}
V(mutex);
}
3 搜索-插入-删除问题。三个线程对一个单链表进行并发的访问,分别进行搜索、插入和删除。搜索线程仅仅读取链表,因此多个搜索线程可以并发。插入线程把数据项插入到链表最后的位置;多个插入线程必须互斥防止同时执行插入操作。但是,一个插入线程可以和多个搜索线程并发执行。最后,删除线程可以从链表中任何一个位置删除数据。一次只能有一个删除线程执行;删除线程之间,删除线程和搜索线程,删除线程和插入线程都不能同时执行。请编写三类线程的同步互斥代码,描述这种三路的分类互斥问题。
Semaphore search_search = 1; // 确保搜索线程之间互斥访问
Semaphore search_delate = 1; // 确保搜索线程与删除线程之间互斥
Semaphore insert_insert = 1; // 确保插入线程之间互斥
Semaphore insert_delate = 1; // 确保插入线程与删除线程之间互斥
int searchers = 0; // 记录搜索线程数量
int inserters = 0; // 记录插入线程数量
Seachers:
while(true) {
P(search_search);
searchers++;
if (searchers == 1)
P(search_delate);
V(search_search);
search();
P(search_search);
searchers--;
if (searcher == 0)
V(search_delate);
V(search_search);
}
Inserters:
while(true) {
P(insert_insert);
inserters++;
if (inserters == 1)
P(insert_delate);
V(insert_insert);
P(insert_insert);
insert();
V(insert_insert);
P(insert_insert);
if (inserters == 0)
V(insert_delate);
V(insert_insert);
}
Deleters:
while(true) {
P(search_delate);
P(insert_delate);
delate();
V(insert_delate);
V(search_delate);
}
4 一个系统有 4 个进程和 5 个可分配资源,当前分配和最大需求如下:
进程 | 已分配资源 | 最大需求 | 可用资源 |
---|---|---|---|
进程A | 10211 | 11213 | 00x12 |
进程B | 20110 | 22210 | |
进程C | 11010 | 21310 | |
进程D | 11110 | 11221 |
若保持该状态是安全状态,那么 x 的最小值是多少?
各进程资源需求矩阵如下:
A 01002
B 02100
C 10300
D 00111
分析 x:
若 x 为 0,资源无法满足任何进程的需求,系统立刻进入不安全状态;
若 x 为 1,进程 D 可分配资源首先运行,D 结束后可用资源向量为 11222,进程 A 可分配资源运行,结束后可用资源向量为 21433,此时进程 C 可分配资源运行,C 结束后可用资源向量为 32443,可满足进程 B 需求,所有进程运行完毕。
故 x 最小值为 1。