【操作系统-进程】PV操作——读者写者问题
文章目录
- 读者写者问题万能模板
- 万能模板 1——读进程优先
- 万能模板 2——读写公平法
- 万能模板 3——写进程优先
- 题目 1:南北过桥问题
- 题目 2:录像厅问题
- 题目 3:更衣问题
读者写者问题万能模板
读者写者问题,其本质就是连续多个同类进程访问同一个临界资源的问题。
第一个进程开始访问临界资源前,需要对资源加上互斥锁,后面的进程再访问时就不用再对资源加互斥锁了,直到最后一个进程访问完后,发现自己是最后一个进程,就解锁互斥锁。这就像一种情况:第一个人进房间时必须顺手开门,后面进来的人和离开的人就不用开门,直到最后一个人离开房间时才需要顺手关门。
代码的通用模板是“三段式”,如下:
int count = 0; // 记录正在访问的进程数量
信号量 busy = 1; // “完成事件”的互斥锁
信号量 mutex = 1; // 变量 count 的互斥锁Process(){while(1){P(mutex);count++; // 访问资源的进程数量加 1if (count == 1){ // (1)如果发现自己是第一个访问的进程,需要负责加锁P(busy);}V(mutex);完成事件; // (2)访问临界资源、完成临界事件P(mutex);count--; // 访问完毕,访问资源的进程数量减 1if (count == 0){ // (3)如果发现自己是最后一个访问的进程,需要负责解锁V(busy);}V(mutex);}
}
理解了最基本的原理后,下面来正式讨论读者写者问题。
【读者写者问题】有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程(只是读数据,不会对数据产生影响,而消费者读数据时,会将数据取走,因此不能两个消费者一起读数据)同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。
因此要求:
- 允许多个读者可以同时对文件执行读操作;
- 只允许一个写者往文件中写信息;
- 任一写者在完成写操作之前不允许其他读者或写者工作;
- 写者执行写操作前,应让已有的读者和写者全部退出。
万能模板 1——读进程优先
即使写者发出了请求写的信号,但是只要还有读者在读取内容,就还允许其他读者继续读取内容,直到所有读者结束读取,才真正开始写。
int count = 0;
信号量 busy = 1; // “读文件”和“写文件”的互斥锁
信号量 mutex = 1; // 变量 count 的互斥锁Reader(){ // 读者进程while(1){P(mutex);count++; if (count == 1){ P(busy);}V(mutex);读文件; P(mutex);count--; if (count == 0){ V(busy);}V(mutex);}
}Writer(){ // 写者进程while(1){P(busy);写文件;V(busy);}
}
如果读者写者到达的顺序是:读者 1–读者2–读者 3–写者 A–读者 4–写者 B–读者 5
,则:
- 读者 1、读者 2、读者 3 到达,busy 加锁,开始读;
- 写者 A 到达,但是读者还在读,未释放 busy 锁,因此不能写;
- 读者 4 到达,可以开始读;
- 写者 B 到达,但是读者还在读,未释放 busy 锁,因此不能写;
- 读者 5 到达,可以开始读;
- 等到读者们都读完,释放 busy 锁,写者才可以开始写。
万能模板 2——读写公平法
读写进程都要排队进行操作文件。即使里面有读进程在操作文件,读进程也要和写进程一起排队。
int count = 0;
信号量 queue = 1; // 实现“读写公平”的互斥锁,可以视为一个队列
信号量 busy = 1; // “读文件”和“写文件”的互斥锁
信号量 mutex = 1; // 变量 count 的互斥锁Reader(){ // 读者进程while(1){P(queue); // 在无写进程请求时不需要进入队列P(mutex); // 该互斥量实际上是多余的,上面语句已经兼有互斥功能count++; if (count == 1){ P(busy);}V(mutex); // 该互斥量实际上是多余的,下面语句已经兼有互斥功能V(queue); // 恢复对共享文件的访问读文件; P(mutex);count--; if (count == 0){ V(busy);}V(mutex);}
}Writer(){ // 写者进程while(1){P(queue); // 在无其他写进程请求时不需要进入队列P(busy);写文件;V(busy);V(queue); // 恢复对共享文件的访问}
}
如果读者写者到达的顺序是:读者 1–读者2–读者 3–写者 A–读者 4–写者 B–读者 5
,则:
- 读者 1、读者 2、读者 3 到达,busy 加锁,开始读;
- 写者 A 到达,queue 加锁,但是读者还在读,busy 锁仍未释放,因此不能写;
- 读者 4 到达,但是读者还在读,queue 和 busy 锁仍未释放,不能开始读;
- 写者 B 到达,queue 锁和 busy 锁仍未释放,因此不能写;
- 读者 5 到达,但是读者还在读,queue 和 busy 锁仍未释放,不能开始读;
- 等到读者 1 到 3 都读完,释放 busy 锁,写者 A 才可以开始写;
- 接下来就是按读者 4、写者 B、读者 5 的顺序依次访问文件。
实际上,读写公平法也可以不用任何除了访问文件外的互斥锁:
信号量 busy = 1; // 也可以视为一个队列Reader(){ // 读者进程while(1){P(busy);读文件;V(busy);}
}Writer(){ // 写者进程while(1){P(busy);写文件;V(busy);}
}
万能模板 3——写进程优先
如果有写者申请写文件,那么在申请之前还在读取文件的读进程可以继续读取,但是如果再有读者申请读取文件,则不能够读取,只有在所有的写者写完之后才可以读取。
int ReaderCount = 0; // 读者数量
int WriterCount = 0; // 写者数量
信号量 Read = 1; // “读文件”的互斥锁
信号量 Write = 1; // “写文件”的互斥锁
信号量 ReaderMutex = 1; // 变量 ReaderCount 的互斥锁
信号量 WriterMutex = 1; // 变量 WriterCount 的互斥锁Reader(){ // 读者进程while(1){P(Read); // 每个读进程都需要对 Read 加锁P(ReaderMutex); // 对 ReadCount 的互斥,实际上,上条语句已经兼有此功能,可以去掉ReaderCount++; if (ReaderCount == 1){ // 如果是第一个读进程P(Write); // 则对写者上锁}V(ReaderMutex); // 对 ReadCount 的互斥,实际上,下条语句已经兼有此功能,可以去掉V(Read); // Read 解锁读文件; P(ReaderMutex); // 对 ReadCount 的互斥ReaderCount--; if (ReaderCount == 0){ // 如果是最后一个读进程V(Write); // 则对写者解锁}V(ReaderMutex); // 对 ReadCount 的互斥}
}Writer(){ // 写者进程while(1){P(WriterMutex); // 对 WriterCount 的互斥WriterCount++; if (WriterCount == 1){ // 如果是第一个写进程P(Read); // 则对读者上锁}V(WriterMutex); // 对 WriterCount 的互斥P(Write); // Write 加锁写文件; V(Write); // Write 解锁P(WriterMutex); // 对 WriterCount 的互斥WriterCount--; if (WriterCount == 0){ // 如果是最后一个写进程V(Read); // 则对读者解锁}V(WriterMutex); // 对 WriterCount 的互斥}
}
如果读者写者到达的顺序是:读者 1–读者2–读者 3–写者 A–读者 4–写者 B–读者 5
,则:
- 读者 1、读者 2、读者 3 到达,Write 加锁,开始读;
- 写者 A 到达,Read 加锁,但是读者还在读,Write 锁仍未释放,因此不能写;
- 读者 4 到达,Read 锁仍未释放,不能开始读;
- 写者 B 到达,Write 锁仍未释放,因此不能写;
- 读者 5 到达,Read 锁仍未释放,不能开始读;
- 等到读者 1 到 3 都读完,释放 Write 锁,写者 A 才可以开始写,写完后 Write 解锁。由于写者 A 不是最后一个写进程,因此 Read 不解锁;
- 写者 B 进行写操作,写完后 Write 解锁,由于写者 B 是最后一个写进程,因此 Read 解锁;
- 读者 4、读者 5 依次进行读操作。
题目 1:南北过桥问题
【题目 1】有桥如下图所示,车流如箭头所示,桥上不允许两车交汇,但允许同方向多辆车依次通过(即桥上可以有多个同方向的车)。用P、V操作实现交通管理以防止桥上堵塞。
【解答】直接套“三段式”,如下:
int count1 = 0; // 北到南的车辆数
int count2 = 0; // 南到北车辆数
信号量 bridge = 1;
信号量 mutex1 = 1;
信号量 mutex2 = 1;北到南(){P(mutex1);count1++;if (count1 == 1){P(bridge);}V(mutex1);北到南过桥;P(mutex1);count1--;if (count1 == 0){V(bridge);}V(mutex1);
}南到北(){P(mutex2);count2++;if (count2 == 1){P(bridge);}V(mutex2);南到北过桥;P(mutex2);count2--;if (count2 == 0){V(bridge);}V(mutex2);
}
题目 2:录像厅问题
【题目 2】假设一个录像厅有 0,1,2 三种不同的录像片可由观众选择放映。录像厅的放映规则为:
- 任何时刻最多只能放映一种录像片,正在放映的录像片是自动循环放映的。最后一个观众主动离开时结束当前录像片的放映。
- 选择当前正在放映录像片的观众可立即进入,允许同时有多位选择同一中录像片的观众同时观看,同时观看的观众数量不受限制。
- 等待观看其他录像片的观众按到达顺序排队,当一种新的录像片开始放映时,所有等待观看该录像片的观众可一次进入录像厅同时观看。
【解答 1】本题也可以直接套“三段式”,如下:
int count0 = 0; // 看影片 0 的观众数
int count1 = 0; // 看影片 1 的观众数
int count2 = 0; // 看影片 2 的观众数
信号量 movie = 1;
信号量 mutex0 = 1;
信号量 mutex1 = 1;
信号量 mutex2 = 1;看影片0的观众(){P(mutex0);count0++;if (count0 == 1){P(movie);}V(mutex0);看影片0;P(mutex0);count0--;if (count0 == 0){V(movie);}V(mutex0);
}看影片1的观众(){P(mutex1);count1++;if (count1 == 1){P(movie);}V(mutex1);看影片1;P(mutex1);count1--;if (count1 == 0){V(movie);}V(mutex1);
}看影片2的观众(){P(mutex2);count2++;if (count2 == 1){P(movie);}V(mutex2);看影片2;P(mutex2);count2--;if (count2 == 0){V(movie);}V(mutex2);
}
【解答 2】借助“写进程优先”的思想,观看某影片的观众在进去前,可以先把要观看其他影片的观众先上锁,让他们暂时阻塞,如下:
int count0 = 0; // 看影片 0 的观众数
int count1 = 0; // 看影片 1 的观众数
int count2 = 0; // 看影片 2 的观众数
信号量 mutex0 = 1; // 影片 0 的互斥锁,兼有对变量 count0 的互斥功能
信号量 mutex1 = 1; // 影片 1 的互斥锁,兼有对变量 count1 的互斥功能
信号量 mutex2 = 1; // 影片 2 的互斥锁,兼有对变量 count2 的互斥功能看影片0的观众(){P(mutex0);count0++;if (count0 == 1){ // 第一个进去的观众把其他影片的观众“挡住”P(mutex1);P(mutex2);}V(mutex0);看影片0;P(mutex0);count0--;if (count0 == 0){ // 最后一个出来的观众允许其他影片的观众进来V(mutex1);V(mutex2);}V(mutex0);
}看影片1的观众(){P(mutex1);count1++;if (count1 == 1){ // 第一个进去的观众把其他影片的观众“挡住”P(mutex0);P(mutex2);}V(mutex1);看影片1;P(mutex1);count1--;if (count1 == 0){ // 最后一个出来的观众允许其他影片的观众进来V(mutex0);V(mutex2);}V(mutex1);
}看影片2的观众(){P(mutex2);count2++;if (count2 == 1){ // 第一个进去的观众把其他影片的观众“挡住”P(mutex0);P(mutex1);}V(mutex2);看影片2;P(mutex2);count2--;if (count2 == 0){ // 最后一个出来的观众允许其他影片的观众进来V(mutex0);V(mutex1);}V(mutex2);
}
看似没毛病吧。然而,事实上这段代码是有问题的,可能会引发死锁,哈哈哈……你发现了吗?
题目 3:更衣问题
【题目 3】某男⼦⾜球俱乐部,有教练、队员若⼲。每次⾜球训练开始之前,教练、球员都需要先进⼊更⾐室换⾐服,可惜俱乐部只有⼀个更⾐室。教练们脸⽪薄,⽆法接受和别⼈共⽤更⾐室。队员们脸⽪厚,可以和其他队员⼀起使⽤更⾐室。如果队员和教练都要使⽤更⾐室,则应该让教练优先。请使⽤ P、V 操作描述上述过程的互斥与同步,并说明所⽤信号量及初值的含义。
【解答】把教练视为写进程,把队员视为读进程,更衣室视为缓冲区,则该题需要实现的“写进程优先”。如下:
int ReaderCount = 0; // 读者数量
int WriterCount = 0; // 写者数量
信号量 Read = 1; // “读文件”的互斥锁
信号量 Write = 1; // “写文件”的互斥锁
信号量 ReaderMutex = 1; // 变量 ReaderCount 的互斥锁
信号量 WriterMutex = 1; // 变量 WriterCount 的互斥锁Reader(){ // 读者进程(相当于教练)while(1){P(Read); // 每个读进程都需要对 Read 加锁P(ReaderMutex); // 对 ReadCount 的互斥ReaderCount++; if (ReaderCount == 1){ // 如果是第一个读进程P(Write); // 则对写者上锁}V(ReaderMutex); // 对 ReadCount 的互斥V(Read); // Read 解锁读文件; P(ReaderMutex); // 对 ReadCount 的互斥ReaderCount--; if (ReaderCount == 0){ // 如果是最后一个读进程V(Write); // 则对写者解锁}V(ReaderMutex); // 对 ReadCount 的互斥}
}Writer(){ // 写者进程(相当于队员)while(1){P(WriterMutex); // 对 WriterCount 的互斥WriterCount++; if (WriterCount == 1){ // 如果是第一个写进程P(Read); // 则对读者上锁}V(WriterMutex); // 对 WriterCount 的互斥P(Write); // Write 加锁写文件; V(Write); // Write 解锁P(WriterMutex); // 对 WriterCount 的互斥WriterCount--; if (WriterCount == 0){ // 如果是最后一个写进程V(Read); // 则对读者解锁}V(WriterMutex); // 对 WriterCount 的互斥}
}
【操作系统-进程】PV操作——读者写者问题相关推荐
- 《OS:PV操作 - 读者写者问题》
经典同步问题 读者写者问题 背景:有多个读者,也有多个写者.要保证其互斥性.要求应用对应的PV操作实现. 定义: P,V操作均为原子操作 原子操作是在执行的过程中,要么全做,要么全不做,不可被CPU打 ...
- PV操作读者写者问题
进程互斥.进程同步,信号量 要求:允许几个读者可以同时读该数据集,而一个写者不能与其他进程(不管是读者还是写者)同时访问该数据集. 两类进程:读进程.写进程 互斥关系:读进程-写进程,写进程-写进程( ...
- 操作系统-进程PV操作
进程是为了完成一项任务,执行一段程式代码,以及为完成这个任务而调用系统的一些资源如cpu.内存等资源,是独立存在的,与其它进程不能共享数据,而线程与进程很相似,颗粒度更小,在进程范围内着重关注cpu的 ...
- 操作系统原理:进程 PV 操作如何计算?全网最全三种前驱图计算类型总结
文章目录 前言 一.PV 操作定义 1.1.P 操作定义 1.2.V 操作定义 二.串联进程(单线前驱图) 2.1.什么是单线前驱图? 2.2.如何计算单线前驱图的 PV? 2.2.1.计算前驱节点 ...
- 【操作系统】PV 操作经典例题---三个进程之间的同步
问题: 总共有 读入.执行.打印 三个进程,试用PV操作描述读入B1打印B2的同步过程. 问题解读: 这个问题就是说了这样一件事:一个输入B1,被操作之后,成为B2,将B2打印.怎样用PV操作来说这件 ...
- 【操作系统】Semaphore处理读者-写者问题
"Reader-Writer"问题 问题描述 问题分析 关系分析 求解思路 信号量设置 问题解决 方案一 方案二 对比 问题描述 有读者和写者两组并发进程,共享一个文件,当两个或以 ...
- 【操作系统】——PV操作
大家都说操作系统中的PV操作部分看不懂,确实我在专业课中学习这门课时,PV操作被列为书中的重点和难点,就是因为它不好理解.当时自己听完课也是一头雾水,到期末考试结束,也没弄明白这是怎么一回事,更没有意 ...
- 【操作系统】PV操作之上下楼梯问题,无饿死
目录 问题描述 版本一 版本二 版本三 问题描述 某教学楼楼梯较窄,为了安全规定课间,一旦有人从上往下走,则不允许任何人从下往上走,但此时可以允许多人同时往下走,反之依然.请应用所学的同步操作完成此问 ...
- 操作系统中PV操作之顾客理发师问题
PV操作:对信号量进行相应操作 S:信号量 P:请求操作,相当于S=S-1:S>=0,进程继续进行 V:释放操作,相当于S=S+1,S>0,进程被唤醒 理发师问题 一个理发师,一把理发椅, ...
最新文章
- 学习使用Bing Maps Silverlight Control(五):离线使用和自定义地图模式
- 什么?分布式事务现在不是都在用么?你还不会?
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | Instrumentation 源码分析 )
- 【AutoML】连续可微分架构如何用于网络结构搜索
- PPT 下载 | 神策数据朱德康:用户中台建设实践解析
- FPGA+NIOS2 Verilog+C 实现一个计算器
- core mysql 延迟加载_mybatis延迟加载及实例讲解
- VMware-workstation安装
- SQL Sever — 导入数据与导出数据到表的方法
- 将2^n (n=1000000) 转化为10进制输出
- 概念学习(Concept learning)
- 51单片机引脚功能介绍
- Arquillian测试框架快速上手教程(四)- 使用Arquillian + Drone + Selenium + Graphene 进行Web自动化测试
- python计算平均分
- f460是多少兆的 zxhn_一个大不同的中兴光猫——ZXHN F460
- cad计算机在哪,Win7系统中cad临时文件保存在哪里
- L1-040 最佳情侣身高差 (10 分)java
- Cesium学习四:使用entity绘制polygon
- sql中intersect_INTERSECT –谓词中被低估的双向
- shell脚本触发企业微信群机器人