(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. kafka笔记——kafka启动

    1. 准备 阿里云Linux服务器一个(Centos7) 腾讯云Linux服务器一个(CentOs7) zookeeper,kafka压缩包 Java环境配置好 要死....脚本之家 2. 安装 zo ...

  2. 使用vuex做列表数据过滤

    功能需求 展示一个表格,表格包含选项有" 姓名 年龄 是否显示"三个列表项 是否显示列表项是可操作开关,点击切换打开/关闭 将表格中开关为打开状态的列表项,在另一个表格中显示 需求 ...

  3. ref以及传值传址的理解

    ref(也包括out)关键字肯定都会用,传值调用和传址调用也是初学写代码时都已经历过的话题,与这相关的还有一些话题,比如值类型和引用类型有什么区别等,但是如果不仔细,可能有一些概念的混淆或者理解不够清 ...

  4. PHP date_timezone_set() 函数

    ------------恢复内容开始------------ 实例 设置 DateTime 对象的时区: <?php$date=date_create("2013-05-25" ...

  5. PHP is_resource() 函数

    is_resource() 函数用于检测变量是否为资源类型. PHP 版本要求: PHP 4, P+-HP 5, PHP 7高佣联盟 www.cgewang.com 语法 bool is_resour ...

  6. PHP asin() 函数

    实例 返回不同数的反正弦: <?phpecho(asin(0.64) . "<br>");echo(asin(-0.4) . "<br>&q ...

  7. 记录一次线上实施snmp

    公司要实施一个部级的项目,我们公司的提供的产品要对接下客户的一个平台监控平台,该监控平台使用snmp,我们公司的产品不支持snmp,所以由我负责在现网实施snmp,记录这次现网 一.生成编译规则 1. ...

  8. maven个人配置

    settings.xml 文件修改一下内容 本地 <localRepository>D:\maven\repository</localRepository> 远程:修改成国内 ...

  9. 一个简单的CPP处理框架

    好久没有在csdn上写过东西了,这么多年,一方面是工作忙,下班到家也没有开过电脑了,要陪小孩玩: 下面分享一段代码,是用CPP做的一个简单的消息(协议)处理框架: 是通过成员函数指针+map来实现的: ...

  10. Python最好IDE:Pycharm使用小技巧总结,让你写代码更为舒适