操作系统——P/V操作例题
1. (生产者—消费者问题)
生产者、消费者共享有个初始为空、大小为n的缓冲区;
只有缓冲区未满时,生产者才能把产品放入缓冲区;
只有缓冲区非空时,消费者才能从中取出产品
semaphore mutex = 1; // 互斥信号量
semaphore empty = n; // 空闲缓冲区数量
semaphore full = 0; // 产品(非空缓冲区)数量
void producer(){
while(true){
生产产品;
P(empty);
P(mutex);
产品放入缓冲区;
V(mutex);
V(full); // 唤醒消费者进程
}
}
void consumer(){
while(true){
P(full);
P(mutex);
从缓冲区取出一个产品;
V(mutex);
V(empty); // 唤醒生产者进程
使用产品;
}
}
2.(吸烟者问题)
假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供
应者就会放另外两种材料再桌上,这个过程一直重复 (让三个抽烟者轮流地抽烟)
semaphore offer1 = 0; // 组合1(纸+胶水)的数量
semaphore offer2 = 0; // 组合2(烟草+胶水)的数量
semaphore offer3 = 0; // 组合3(烟草+纸)的数量
semaphore finish = 0; // 抽烟是否完成
int i = 0; // 用于轮流提供
void provider(){
while(true){
if(i == 0){
将组合1放桌上;
V(offer1);
}
else if(i == 1){
将组合2放桌上;
V(offer2);
}
else if(i == 2){
将组合3放桌上;
V(offer3);
}
i = (i+1) % 3;
P(finish);
}
}
void smoker1(){
while(true){
P(offer1);
拿走组合1,抽掉;
V(finish);
}
}
void smoker2(){
while(true){
P(offer2);
拿走组合2,抽掉;
V(finish);
}
}
void smoker3(){
while(true){
P(offer3);
拿走组合3,抽掉;
V(finish);
}
}
3.(读者—写者问题)
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:
①充许多个读者可以同时对文件执行读操作:
②只充许一个写者往文件中写信息:
③任一写者在完成写操作之前不允许其他读者或写者工作:
④写者执行写操作前,应让已有的读者和写者全部退出。
semaphore rw = 1; // 写文件的互斥访问
int count = 0; // 记录当前有几个读进程在访问
semaphore mutex = 1; // count的互斥访问
void writer(){
while(true){
P(rw);
写文件;
V(rw);
}
}
void reader(){
while(true){
P(mutex);
if(count == 0){
P(rw);
}
count++;
V(mutex);
读文件;
P(mutex);
count--;
if(count == 0){
V(rw);
}
V(mutex);
}
}
4.(哲学家就餐问题)
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上有一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
要求使用以下策略解决死锁:仅当哲学家左右两支筷子都可用时才允许他抓起筷子。
semaphore chopstick[5] = {1,1,1,1,1};
semaphore mutex = 1; // 互斥取筷子
void Pi(){
while(true){
P(mutex);
P(chopstick[i]); // 拿左筷子
P(chopstick[(i+1)%5]); // 拿右筷子
V(mutex);
吃饭;
V(chopstick[i]); // 放左筷子
V(chopstick[(i+1)%5]); // 放右筷子
思考;
}
}
5.(简单奇偶数统计)
缓冲区的容量为N。
P1每次用produce()生成一个正整数并用put()将其放入缓冲区;
P2每次用getOdd()从缓冲区中取出一个奇数并用countOdd()统计奇数的个数;
P3每次用getEven()从缓冲区中取出一个偶数并用countEven()统计偶数的个数。
semaphore empty = N; // 缓冲区空闲量
semaphore mutex = 1; // 互斥访问缓冲区
semaphore odd = 0; // 奇数统计
semaphore even = 0; // 偶数统计
void P1(){
while(true){
int i = produce();
if(i%2 == 0){
P(mutex);
put();
V(mutex);
V(even);
}
else{
P(mutex);
put();
V(mutex);
V(odd);
}
}
}
void P2(){
while(true){
P(odd);
P(mutex);
getOdd();
countOdd();
V(mutex);
V(empty);
}
}
void P3(){
while(true){
P(even);
P(mutex);
getEven();
countEven();
V(mutex);
V(empty);
}
}
6.(桥梁通行)
桥上不允许有两车相向而行,但允许同方向最多五辆车通行。使用信号量操作实现交通管理。(提示:进程可分为两类:自东向西的车辆和自西向东的车辆)
semaphore bridge = 1; // 行车方向的互斥访问
semaphore empty = 5; // 单向剩余容量
semaphore mutex_west = 1;
semaphore mutex_east = 1;
int west_count = 0; // 自西向东的第几辆车
int east_count = 0; // 自东向西的第几辆车
void WestToEast(){
while(true){
P(mutex_west);
if(west_count == 0){ // 第一个上桥
P(bridge);
}
west_count++;
V(mutex-west);
P(empty);
过桥;
V(empty);
P(mutex_west);
west_count--;
if(west_count == 0){ // 最后一个上桥
V(bridge);
}
V(mutex-west);
}
}
void EastToWest(){
while(true){
P(mutex_east);
if(east_count == 0){ // 第一个上桥
P(bridge);
}
east_count++;
V(mutex-east);
P(empty);
过桥;
V(empty);
P(mutex_east);
east_count--;
if(east_count == 0){ // 最后一个上桥
V(bridge);
}
V(mutex-east);
}
}
7.(图书馆登记)
有一阅览室,共有100个座位。读者进入时必须现在登记表上进行登记。该表表目设有座位号和读者名;离开时需要将其登记项擦除。
semaphore seats = 100;
semaphore mutex = 1;
void lib(){
while(true){
P(seats); // 占有座位
P(mutex);
登记信息;
V(mutex);
阅读;
P(mutex);
注销信息;
V(mutex);
V(seats); // 释放座位
}
}
8.(考场)
假设把学生和监考老师都看做进程,学生有N人,教师有1人。考场门口每次只能进出一个人,进考场的原则是先来先进。当N个学生都进入了考场后,教师才能发卷子。学生交卷后即可离开考场,教师要等收上全部卷子后封装才能离开考场。
semaphore door = 1; // 是否能进出门
semaphore stduentReady = 0; // 学生是否到齐
semaphore examBegin = 0; // 考试开始
semaphore examEnd = 0; // 考试结束
int sudentNum = 0; // 学生数量
semaphore mutex1 = 1; // 学生人数统计互斥
int paper = 0; // 已交试卷数
semaphore mutex2 = 1; // 试卷数统计互斥
void student(){
while(true){
P(door);
进门;
V(door);
P(mutex1);
studentNum++;
if(studentNum == N){
V(studentReady); // 触发开始考试
}
V(mutex1);
P(examBegin); // 等待考试开始
考试;
交卷;
P(mutex2);
paper++;
if(paper == N){
V(examEnd);
}
V(mutex2);
P(door);
出门;
V(door);
}
}
void teacher(){
while(true){
P(door);
进门;
V(door);
P(studentReady);
发试卷;
V(examBegin);
P(examEnd); // 等待考试结束
封装试卷;
P(door);
出门;
V(door);
}
}