(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. SpringMVC文件上传下载(单文件、多文件)

    前言 大家好,我是bigsai,今天我们学习Springmvc的文件上传下载. 文件上传和下载是互联网web应用非常重要的组成部分,它是信息交互传输的重要渠道之一.你可能经常在网页上传下载文件,你可能 ...

  2. Python基础教程 (第2+3 版)打包pdf|内附网盘链接提取码

                <Python基础教程 第3版>包括Python程序设计的方方面面:首先,从Python的安装开始,随后介绍了Python的基础知识和基本概念,包括列表.元组.字符 ...

  3. odoo本地pycham环境搭建(mac)

    本文以odoo12为例配置本地环境,注意不是docker环境 1.安装pycharm(推荐2020.1版本,破解地址:https://www.cnblogs.com/xuexianqi/p/12767 ...

  4. Requests接口测试库-官网快速上手

    Requests 一个发送HTTP请求的库基于urllib3,相比自带的库,提供了更高效简洁的可用方法,测试从业者用来做接口测试的一个好工具 文章内容均来自官网:https://requests.re ...

  5. python 把多个list合并为dataframe并输出到csv文件

    import pandas as pd a = [1,2,3] b = ['a','b','c'] test = pd.DataFrame({'a_list':a,'b_list':b}) 将两个列表 ...

  6. SeekBar滑动时,progress数值不连续

    问题描述 logcat 你是否也遇见过这样的情况,SeekBar的进度不连续 这是我在做一个编辑图片的APP时,观察我打印的log,发现progress不是连续的 这时候可能就有人问:是你代码写的不对 ...

  7. 22-关键字:super

    1.super 关键字可以理解为:父类的 2.可以用来调用的结构: 属性.方法.构造器 3.super调用属性.方法: 3.1 我们可以在子类的方法或构造器中.通过使用"super.属性&q ...

  8. 移动物体监控系统-sprint4嵌入式web服务器开发

    一.BOA嵌入式服务器的移植 step1:下载BOA服务器并解压,进入boa下面的src目录,执行./configure生成必须的配置文件以及Makefile step2:修改Makefile文件 c ...

  9. 008_用go语言实现简单的冒泡排序

    冒泡排序是各个语言中的基本排序算法,本次我们用go语言实现简单的冒泡排序 package main import "fmt" // [13,10,5,7,2] // [10,13, ...

  10. java_Collection、Map、泛型的使用

    Collection集合 集合按照其存储结构可以分为两大类,分别是 单列集合 java.util.Collection 双列集合 java.util.Map Collection:单列集合类的根接口, ...