(1)阅览室问题:加入阅览室入口有一本登记册,每个人都必须按顺序签名进去。

想法:登记册可以用结构数组A[]表示,包含name和number。此外,还需要信号量seatcount表示剩余座位数。
使用信号量mutex约束每次只有一个人能修改登记册
struct {
char name[];
int number;
}A[];
semaphore mutex = ; //控制A[]被修改的信号量
semaphore seatcount = ; //剩余的座位数
int i;
for(i=; i<; i++) {
A[i].number=i;
A[i].nume=null;
}
cobegin
process readeri(char readername[]) {
P(seatcount);
P(mutex);
for(int i=; i<; i++) {
if(A[i].name==null) A[i].name=readername;
reader get the seat number i;
}
V(mutex);
{进入阅览室座位号i,坐下读书};
P(mutex);
A[i].name = null;
V(mutex);
V(seatcount);
}
coend
(2)四个进程Pi(i=0…3)和四个信箱Mj(j=0…3),进程间借助相邻信箱传递消息,即Pi每次从Mi中取一条消息,经加工后送入M(i+1)mod4,其中M0、M1、M2、M3分别可存放3、3、2、2个消息。初始状态下,M0装了三条消息,其余为空。试以P、V操作为工具,写出Pi(i=0…3)的同步工作算法。
想法:说穿了还是有缓冲区的生产者消费者问题,每个信箱需要用信号量empty表示剩余空间、full表示剩余信件。此外还需要int数in、out指明信箱中存取信的位置,以及对应信号量mutex。
semaphore mutex1 = mutex2 = mutex3 = mutex0 = ; //约束每个信箱同一时间只能有一个进程操作
semaphore empty0 = , empty1 = , empty2 = empty3 =; //信箱剩余空间
semaphore full0 = , full1 = full2 = full3 =; //信箱剩余信件数
int in0 = in1 = in2 = in3 = out0 = out1 = out2 = out3 =; //信箱中存、取信的位置,初始均为0
cobegin
process P0( ) {
while(true) {
P(full0);
P(mutex0);
{从M0[out0]取一条消息};
out0 = ( out0 + ) % ;
V(mutex0);
V(empty0);
{加工消息};
P(empty1);
P(mutex1);
{消息存M1[in1]};
in1 = ( in1 + ) % ;
V(mutex1);
V(full1);
}
}
/*P1-P3略*/
coend
(3)今有k个进程,它们的标号依次为1~k,如果允许它们同时读文件file,但必须满足条件:参加同时读文件的进程的标号之和需小于M(k<M)
想法:用一个数numbersum记录当前读文件的进程标号之和,通过信号量mutex实现对其的互斥操作
如果进程发现自己不能运行,就要P(waits)把自己阻塞,阻塞后因为其还在numbersum的临界区内,因此其它进程也进不来了;每当读文件完成,释放一个等待的进程;被释放的进程再次检测自己能否运行,不能的话继续P(waits)把自己阻塞
semaphore waits = ;
Semaphore mutex = ;
int numbersum = ;
cobegin
process readeri(int number) {
P(mutex);
while(numbersum+number>=M) {
V(mutex);
P(waits);
}
numbersum = numbersum + number;
V(mutex);
Read file;
P(mutex);
numbersum = numbersum - number;
V(waits);
V(mutex);
}
coend
(5)轮流捡黑、白棋子:其实就是最简单的生产者消费者问题
semaphore s1 = ; //可捡白子
semaphore s2 = ; //可捡黑子
process p1() {
while(true) {
P(s1);
捡白子;
V(s2);
}
}
process p2() {
while(true) {
P(s2);
捡白子;
V(s1);
}
}
南大13年真题:A捡黑子并计数,B捡白子并计数。不要求轮流捡,但要求互斥捡。C等待AB完成后,合计计数。
想法:通过互斥信号量mutex实现A和B互斥捡棋子。计数器则不需要互斥,因为黑子、白子是分两个计数器;A和B计数完成后各自V(allow),从而允许C工作
Semaphore allow = -;
Semaphore mutex = ;
int count = count_black = count_black = ;
process A(){
while(true){
P(mutex);
get(black);
V(mutex);
if(取到了){count_black++;}
else break;
}
V(allow);
}
process B(){
while(true){
P(mutex);
get(write);
V(mutex);
if(取到了){count_write++;}
else break;
}
V(allow);
}
process C(){
P(allow);
count = count_black + count_write;
printf();
}
(6)n1个进程通过m个缓冲区向n2个缓冲区发消息,每条消息n2个接收进程都要各自接收一次。
思路:课本答案的做法是把这一组缓冲区看成n2组缓冲区(每组m个),每个发送进程需要同时写n2个缓冲区。但是我觉得答案做法很迷啊,m个缓冲区直接被它强行变成了n2*m个缓冲区,每次写一个、接收n2次,变成了每次写n2个、接收n2次。而且答案明明把缓冲区分为n2组,但是只有一个信号量mutex实现对缓冲区操作的互斥。
semaphore mutex , empty[n2] , full[n2];
int i;
mutex = ;
for(i=; i<n2; i++) {
empty[i]=m;
full[i]=;
}
cobegin
send() {
for(int i=;i<n2;i++) {
P(empty[i]);
P(mutex);
{将消息放入缓冲区;}
V(mutex);
}
for(int i=;i<n2;i++){
V(full[i]);
}
}
receive() {
for(int i=;i<n2;i++) {
P(full[i]);
P(mutex);
{从缓冲区中取出信息;}
V(mutex);
}
for(int i=;i<n2;i++) {
V(empty[i]);
}
}
coend
(7)生产者进程每次写3个缓冲区,消费者进程每次读一个缓冲区
思路:答案的思路是通过信号量s1控制每次只允许一个生产者写,通过信号量s2控制每次只允许一个消费者读。因此本题生产者和消费者可以同时工作。
定义了一个初始为0的int数count,每次消费都将其加1,每三次消费之后count达到3,才V(sput)一次,允许一次生产;每次生产之后进行三次V(sget)允许三次消费。
int buf[];
int count = getptr = putptr = ;
semaphore s1 = s2 = ;
Semaphore sput = ;
Semaphore sget = ;
cobegin
process producer_i() {
while(true) {
P(sput);
P(s1);
buf[putptr] = ;
putptr = ( putptr + ) % ;
buf[putptr] = ;
putptr = ( putptr + ) % ;
buf[putptr] = ;
putptr = ( putptr + ) % ;
V(sget);
V(sget);
V(sget);
V(s1);
}
}
process consumer_j() {
int y;
while(true) {
P(sget);
P(s2);
y = buf[getptr];
getptr = ( getptr + ) % ;
count++;
if(count==){
count = ;
V(sput);
}
V(s2);
消费整数y;
}
}
coend
(8)有三组工人和N个槽,第一组工人生产车架,第二组工人生产车轮,第三组工人用车架和四个车轮生产一辆车
思路:其实就是上一题的生产者消费者问题的加强版,可以把N个槽分为N/5、4N/5两部分,分别装车架和车轮,否则可能会出现装满车架或车轮的情况。
通过信号量mutex1控制每次只有一个进程操作第一个槽(即只有1个生产者放车架或1个消费者拿车架);通过mutex2控制每次只有一个进程操作第二个槽(即只有一个生产者放车轮或1个消费者拿车轮)。
每生产一个车架就可以直接拿(不需要像车轮那样通过计数器count控制),因此每次生产一个车架都V(s3)一次。
每生产四个车轮才能拿一次,因此定义了一个初始为0的int数count,每次生产车轮都将其加1,count达到4时才V(s4)一次。因为有mutex2的存在,因此每次只有一个进程能修改count。
semaphore mutex1 = mutex2 = ;
semaphore s1 = N/ , s2 = 4N/ , s3 = s4 = ;
int count = ;
int in1 = in2 = out1 = out2 = ;
cobegin
process worker1() {
while(true) {
加工一个车架;
P(s1);
P(mutex1);
车架放入box[in1];
in1 = (in1 +) % (N/);
V(mutex1);
V(s3);
}
process worker2() {
while(true) {
加工一个车轮;
P(s2);
P(mutex2);
车架放入box[in2];
in2 = (in2 +) % (4N/);
count = count + ;
if(count==) {
count = ;
V(s4);
}
V(mutex2);
}
process worker3() {
while(true) {
P(s3);
P(mutex1);
从box[out1]拿车架;
out1 = (out1 + ) % (N/);
V(mutex1);
V(s1);
P(s4);
P(mutex2);
从box[out2]开始取四个车轮;
out2 = (out2 + ) % (4N/);
V(s2);
V(mutex2);
装配车子;
}
}
ceend
(9)有一个仓库,可存放X、Y两种产品,仓库的存储空间足够大,但要求:(1) 每次只能存入一种产品X或Y, (2) 满足-N<X-Y<M
想法:可以设置两个信号量来控制X、Y产品的存放数量关系:
sx表示当前允许X产品比Y产品多入库的数量,即在当前库存量和Y产品不入库的情况下,还可以允许sx个X产品入库,初始时,若不放Y而仅放X产品,则sx最多为M-1个;
sy表示当前允许Y产品比X产品多入库的数量,即在当前库存量和X产品不入库的情况下,还可以允许sy个Y产品入库,初始时,若不放X而仅放Y产品,则sy最多为N-1个。
当往库中存放入一个X产品时,则允许存入Y产品的数量也增加1,故信号量sy应加1;当往库中存放入一个Y产品时,则允许存入X产品的数量也增加1,故信号量sx应加1。
semaphore mutex=;
semaphore sx = M-;
semaphore sy = N-;
cobegin
process storeX( ) {
while(true) {
P(sx);
P(mutex);
{将X产品入库};
V(mutex);
V(sy);
}
}
process storeY( ) {
while(true) {
P(sy);
P(mutex);
{将Y产品入库};
V(mutex);
V(sx);
}
}
coend
(10)有一个仓库,可放入A、B两种产品,最大库容量各为m个,生产车间不断地取A、B进行装配,每次各取一个。为了零件腐蚀,必须按照先入库者先出库的顺序。有两组供应商分别不断地供应A和B,每次一个。为了保证配套和库存合理,当某种零件比另一种超过n个时,暂停对数量大的零件的进货。
想法:这题实际是上一题的强化版,按照题意一共四种约束关系:0≤A≤m、0≤B≤m、B-A≤n、A-B≤n,分别通过信号量empty1、full1、empty2、full2、sa、sb进行控制。
答案是通过mutex约束每次只有一个进程操作仓库。其实也可以把约束条件放得更宽泛些。
semaphore empty1 , empty2 , full1 , full2 , mutex , sa , sb;
int in1 , in2 , out1 , out2;
empty1 = empty2 = m; //剩余可放空间
full1 = full2 = ; //剩余产品数
sa = sb = n;
mutex = ;
in1 = in2 = out1 = out2 = ;
cobegin
process put_A() {
while(true) {
P(empty1);
P(sa);
P(mutex);
把A零件放入buffA[in1];
in1 = (in1 + ) % m;
V(mutex);
V(sb);
V(full1);
}
}
process put_B() {
while(true) {
P(empty2);
P(sb);
P(mutex);
把B零件放入buffB[in2];
in2 = (in2 + ) % m;
V(mutex);
V(sa);
V(full2);
}
}
process get() {
while(true) {
P(full1);
P(full2);
P(mutex);
从buffA[out1]取A零件;
从buffB[out2]取B零件;
out1 = (out1 + ) % m;
out2 = (out2 + ) % m;
V(mutex);
V(empty1);
V(empty2);
把A和B装配成产品;
}
}
coend
因为装配时A和B各取一件,所以对它们的相对关系并无影响,因为无需对信号量sa和sb进行修改。
答案用了信号量mutex约束三个进程不能同时工作,其实我觉得应该改用三个信号量。
(11)能容纳500人的博物馆,每次只能一个人进出
思路:使用mutex约束每次只有一个人使用门。本题必须注意,进门与出门操作必须在P(empty)和V(empty)之间的临界区内,即有空位才能进门,出门后才释放空位
Semaphore empty = ;
Semaphore mutex = ;
cobegin
process_i(){
P(empty);
P(mutex);
进门;
V(mutex);
参观;
P(mutex);
出门;
V(mutex);
V(empty);
}
(12)三个线程增加互斥条件
typedef struct{
float a;
float b;
}cnum;
cnum x , y ,z;
cnum add(cnum p ,cnum q){
cnum s;
s.a = p.a + q.a;
s.b = s.b + q.b;
return s;
}
想法:本题先看代码,thread1和thread2会修改w,但是w是它们自身创建的,其它线程也没有使用到;而thread3则修改了z、y;
thread3会修改z,而thread2会访问z,必须定义信号量使它们互斥访问z;
thread3会修改y,而thread1和thread2都会访问y,因此需要定义互斥信号量mutex_y1使thread1和thread3对y互斥访问、定义互斥信号量mutex_y2使thread2和thread3对y互斥访问(thread2和thread3不需要互斥y)
Semaphore mutex_y1 = ;  //线程1、3对y的互斥访问
Semaphore mutex_y2 = ; //线程2、3对y的互斥访问
Semaphore mutex_z = ; //线程2、3对z的互斥访问 thread1{
cnum w;
P(mutex_y1);
w = add(x , y);
V(mutex_y1);
}
thread2{
cnum w;
P(mutex_y2);
P(mutex_z);
w = add(y , z);
V(mutex_z);
V(mutex_y2);
}
thread3{
cnum w;
w.a = ;
w.b = ;
P(mutex_z);
z = add(z , w);
V(mutex_z);
P(mutex_y1);
P(mutex_y2)
y = add(y , z);
V(mutex_y1);
V(mutex_y2);
}
(13)14年南大真题:缓冲区可放2000字节,P进程读入数据到缓冲区,Q1、Q2从缓冲区取数据并计算加工,并把结果打印出来。
题目给的子程序:read20()从输入设备读20个字数据到缓冲区;
                             get20()从缓冲区取20字节;
                             comp40t30()计算加工40个字得到结果30字节;
                             print15()打印15字节
Semaphore mutex = ;
Sempahore full = ;
Semaphore empty = ;
process P(){
P(empty);
P(mutex);
read20();
V(mutex);
V(full);
}
Process Q1(){
P(full); get20();
P(full); get20();
comp40t30();
V(empty); print15;
V(empty); print15;
}

操作系统-PV习题的更多相关文章

  1. linux操作系统 - 综合习题

    登录超级用户,完成以下操作: [linux@slave053 ~]$ su - 1.用户和组群管理(本大题共5小题,共10分) (1)创建两个用户tangseng,monkey,并指定密码为12345 ...

  2. 操作系统-PV操作的原理和几种常见问题

    信号量是一种变量类型,用一个记录型数据结构表示,有两个分量:信号量的值和信号量队列指针 除了赋初值外,信号量仅能通过同步原语PV对其进行操作 s.value为正时,此值为封锁进程前对s信号量可施行的P ...

  3. 操作系统PV编程题目总结一

    1.今有一个文件F供进程共享,现把这些进程分为A.B两组,规定同组的进程可以同时读文件F:但当有A组(或B组)的进程在读文件F时就不允许B组(或A组)的进程读文件F.试用P.V操作(记录型信号量)来进 ...

  4. 操作系统实验——PV操作实现生产者消费者模型

    操作系统PV操作之--生产者消费者模型 个人博客主页 参考资料: Java实现PV操作 | 生产者与消费者 浙大公开课 在操作系统的多进程.多线程操作中经常会有因为同步.互斥等等问题引发出的一系列问题 ...

  5. Python笔记(十一):多线程

    (二)和(三)不感兴趣的可以跳过,这里参考了<深入理解计算机系统>第一章和<Python核心编程>第四章 (一)      多线程编程 一个程序包含多个子任务,并且子任务之间相 ...

  6. 零基础一年拿下BAT三家offer

    背景 1.本人本科一本双非垫底的那种,硕士211.本硕电子通信,完全0基础,转行一年. 2.研一上第一学期上课+外派到老师合作公司写MATLAB.去年4月开始学习Java. 起步 1.实话说,刚决定转 ...

  7. log4j 多进程配置要注意的

    多进程写日志文件 方法一: 解决log4j公用配置文件,多进程同时写同一个log文件,因存在操作系统pv操作问题, 导致部分日志丢失.解决方案是不同的进程写不同的log文件 测试于:Log4j 1.2 ...

  8. Operating System:信号量

    pv原语操作(1)操作系统PV意思:PV操作与信号量的处理相关,P表示通过的意度思,V表示释放的意思.(2)p操作和v操作是不可中断问的程序段,称为原语.如果将信号量看作共享变量,则pv操作为其临界区 ...

  9. 整型信号量和PV操作(计算机操作系统)

    在整型信号量机制中,信号量被定义为一个整形变量.除初始化外,仅能通过两个标准的原子操作Wait(S)和Signal(S)来访问.其通常分别被称为P.V操作. 描述如下: P操作:S=S-1:如果S小于 ...

随机推荐

  1. 删除GIT中的.DS_Store

    转载自:https://www.jianshu.com/p/fdaa8be7f6c3 .DS_Store 是什么 使用 Mac 的用户可能会注意到,系统经常会自动在每个目录生成一个隐藏的 .DS_St ...

  2. Day15_redis安装及配置

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 redi ...

  3. 省选模拟赛 4.26 T1 dp 线段树优化dp

    LINK:T1 算是一道中档题 考试的时候脑残了 不仅没写优化 连暴力都打挂了. 容易发现一个性质 那就是同一格子不会被两种以上的颜色染.(颜色就三种. 通过这个性质就可以进行dp了.先按照左端点排序 ...

  4. Typora+PicGo-Core(command line)+SMMS、github、gitee实现Typora图片上传到图床

    Typora+PicGo-Core(command line)+SMMS.github.gitee实现Typora图片上传到图床 1 安装插件2 配置config.json    2.1 设置SMMS ...

  5. idea修改maven项目版本号

    1 先安装插件 2 控制台执行命令  mvn build-helper:parse-version versions:set -DnewVersion=1.1-SNAPSHOT versions:co ...

  6. Canal简介

    以下内容主要摘自Canal 官方wiki和网友博客:https://www.jianshu.com/p/6299048fad66 一.背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨 ...

  7. 三个技巧帮助Docker镜像瘦身

    在构建Docker容器时,应该尽量想办法获得体积更小的镜像,因为传输和部署体积较小的镜像速度更快. 但RUN语句总是会创建一个新层,而且在生成镜像之前还需要使用很多中间文件,在这种情况下,该如何获得体 ...

  8. day2. 六大基本数据类型简介

    一.基本数据类型 Number 数字类型 (int float bool complex) str 字符串类型 list 列表类型 tuple 元组类型 set 集合类型 dict 字典类型 二.Nu ...

  9. Android后台数据接口交互实现注册功能

    首先,在ecplise里面新建一个叫做TestServices的web工程.在WebContent--WEB-INF--libs文件夹下导入两个jar包:mysql-connector-java-6. ...

  10. 为什么overflow:hidden能达到清除浮动的目的?

    1. 什么是浮动 <精通CSS>(第3版)关于浮动的描述: 浮动盒子可以向左或向右移动,直到其外边沿接触包含块的外边沿,或接触另一个浮动盒子的外边沿. 浮动盒子也会脱离常规文档流,因此常规 ...