读者写者问题详解 操作系统

article/2025/9/30 9:54:00

2.16 读者写者问题

抽象解释

  • 多个进程访问一个共享的数据区
  • 读者(读进程)只能读数据,写者(写进程)只能写数据
  • 适用于数据库、文件、内存、寄存器等数据区的访问模型
  • 如12306购票系统,由于用户量庞大和数据量巨大,不可避免地会出现多个进程同时查询(读)或修改(写)同一条数据的情况

2.16.1 读者写者问题的三个约束条件

  • 读者之间不互斥(你和室友可以同时查看元旦那天早上7点的高铁信息
  • 写者之间必须互斥(你和室友不能同时申请购买元旦那天早上七点G1234的6D号位置
  • 读者写者之间也互斥(假如你正在买G1234的6D座位,你的室友无法读到该位置的售票信息

2.16.2 读者写者问题VS生产者消费者问题

  • 能不能用生产者消费者问题解决读者写者问题?

不能
像生/消问题那样严格互斥读者写者虽然可以保证数据的正确,却无法实现同时读的特点

  • 如何判断一个问题是生产者消费者问题,还是读者写者问题?
  1. 生产者消费者问题:数据消费后就没有了;读者写者问题:数据可多次读
  2. 生产者消费者问题:消费者彼此互斥;读者写者问题:读者可以同时读

2.16.3 解决读者写者问题的三种方案

策略一 读者优先
  • 有读者在读的话,随后的读者可以进入临界区一起读
  • 待临界区全部读者退出后再轮到下一个写者
  • 有越过写者的现象,造成写者饥饿
变量设置
  • wsem:互斥信号量
  • readcount:统计同时读的readers
  • x:对readcount的修改加锁
伪代码
	int readcount=0;semaphore x = 1, wsem=1;void reader() { while (1) {P(x);readcount++;if (readcount==1) P(wsem); //第一个读者会执行此if语句,随后的会跳过P(wsem)直接进入临界区V(x);READ;P(x);readcount--;if (readcount==0) V(wsem);//最后退出的读者执行此语句,释放临界区权限V(x);}}void writer() {while (1) {P(wsem);WRITE;V(wsem);}}
读者优先的相关思考
  1. Ⅰ、Ⅱ语句能否互换?
    答:不能,readcount的判断一定要在锁内,否则会出现读写不互斥:假设此时写者在临界区,第一个读者到来后readcount++,阻塞在P(wsem),第二个读者到来后直接可以修改count++,导致跨过P(wsem)直接进入临界区,读写不互斥。这时失去的条件是:先有一个读者进入临界区时等其进入后后面的读者才能修改count。
  2. Ⅲ、Ⅳ语句能否互换?
    答:不能,交换后考虑最后一个进程退出时又到来一个读者进程的情况:交换后readcount=0,尚未判断if时,读者仍会进入临界区,判断后释放临界区权限,写者也进入临界区,这时读写不互斥。这时失去的条件是:最后一个读者退出临界区时等其退出后才能修改count
  3. 考虑如下进程序列(设序列中从右到左为进程先后到达顺序),下列哪一种情况下可能存在写者饥饿
    1.R R R
    2.W W W
    3.R W
    4.R R W
    5.R R W R
    6.W W R
    7.W R R W
    答:5.RRWR时有一个R先到临界区,后面的读者进程在等待时会越过P(wsem)直接进入临界区,也就是越过了W,造成写者饥饿
策略二 公平优先
  • 有读者在读的话,下一个写者之前的读者可以进入临界区一起读
  • 写过程中,其他到来的进程按顺序处理
  • 没有越过写者的现象,不会造成写者饥饿
变量设置
  • wsem:互斥信号量
  • readcount:统计同时读的readers
  • x:对readcount的修改加锁
  • wrsem:互斥信号量,reader和writer在这里排队,用处是在读者优先的基础上,不让读者越过写者
伪代码
	int readcount=0, semaphore x=l, wrsem=1, wsem=l;
void reader() {while (true) {P(wrsem);P(x);readercount++;if (readercount == 1)P(wsem);V(x);V(wrsem);READ;P(x);readercount--;if (readercount == 0)V(wsem);V(x);}
}
void writer() {while (true) {P(wrsem);P(wsem);WRITE;V(wsem);V(wrsem);}
}
与读者优先相比

在读者优先中,wsem只对第一个读者起阻塞作用,后续读者不受其影响。为了保证按照到达顺序处理,故公平优先方式设置wrsem,读者/写者按到达顺序在wrsem上排队。

策略三 写者优先
  • 有写者声明要写时,不允许读者再进入临界区
  • 降低了并发度
  • 有越过读者的现象,会造成读者饥饿
变量设置
  • rsem:互斥信号量,当至少有一个写者申请写数据时,互斥新的读者进入读数据
  • 第一个写者受rsem影响,一旦有第一个写者,后续写者不受rsem其影响。但是读者需要在rsem上排队
  • writecount:用于控制rsem对写者的控制
  • y:对writecount的修改加锁
伪代码
int readcount = 0, writecount = 0;
semaphore x=l, y= 1, wsem=1, rsem=l;void reader( ) {while (1) {P(rsem);P(x);readcount++;if (readcount ==1) P(wsem);V(x);V(rsem);READ;P(x);readcount--;if (readcount ==0) V(wsem);V(x);}}
void writer( ) {while (1) {P(y);writecount++;if (writecount ==1) P(rsem);V(y);P(wsem);WRITE;V(wsem);P(y);writecount--;if (writecount==0) V(rsem);V(y);}
}
与公平优先相比

在公平优先中,读者和写者都会受到wrsem的限制,而写者优先中,由于增加了if (writecount ==1) P(rsem)的语句,当写者到来时会比读者优先进入临界区,但WRRRR的情况写者不会优先

策略四 写者优先改进
  • 为了解决WRRRR中W不能优先的问题
变量设置
  • 沿用写者优先的变量
  • 增加z信号量,仅对写者有作用,让读者队列在z上排队,只有一个读者在rsem上排队
伪代码
int readcount=0,writecount=0; 
semaphore x=l, y= 1,z=1,wsem=1,rsem=l;void reader( ) {while (1) {P(z);P(rsem);P(x);readcount++;if (readcount ==1) P(wsem);V(x);V(rsem)V(z);READ;P(x);readcount--;if (readcount ==0) V(wsem);V(x);}}
void writer( ) {while (1) {P(y);writecount++;if (writecount ==1) P(rsem);V(y);P(wsem);WRITE;V(wsem);P(y);writecount--;if (writecount==0) V(rsem);V(y);}
}
写者优先改进方法的思考
  1. z信号量起到了什么作用?
  • 在rsem上不允许建造读进程的长队列,否则写进程将不能跳过这个队列.
  • 允许一个读进程在rsem上排队,其他读进程在信号量z上排队
  1. P(z)和P(rsem)能否互换位置?
    不能, 否则P(z)失去限制作用

2.16.4 读者写者问题示例


示例一
情境描述
  • 东西方向的独木桥,仅容一人过,不允许停留
  • 东西方向都有人在等着过桥

请用P、V操作来实现东西两端行人过桥问题

分析
  • 简单的写者互斥问题
  • 多个写者共享数据
  • 行人都是写者,桥是数据
  • 信号量
  • s:互斥信号量
伪代码
semaphore s = 1;                       //互斥信号量void east_west( )
{while (true) {P(s);                                           //互斥其他人过桥walk across the bridge from east to west;      //行人从东向西过桥V(s);                                          //允许其他人过桥}
}void west_east( )
{while (true) {P(s);                                         //互斥其他人过桥walk across the bridge from west to east;      //行人从西向东过桥V(s);                                           //允许其他人过桥}
}

示例二
情境描述
  • 东西方向的独木桥,仅容一人过,不允许停留
  • 东西方向都有人在等着过桥
  • 同一方向的行人可以连续过桥,另一方的行人必须等待

请用P、V操作来实现东西两端行人过桥问题

分析
  • 读者优先问题
  • 行人首先上桥的一方为读者,另一方为写者,桥是数据
  • 信号量
  • x:互斥信号量,互斥读者写者
  • countR:统计读者数目(同时在桥上的行人数目)
  • mutexR:对变量countR加锁
伪代码
int countA=0, countB=0;
semaphore x=1, mutexA=1, mutexB=1;void east_west() { while (1) {P(mutexA);countA++;if (countA==1) P(x); V(mutexA);walk across the bridge from east to west;P(mutexA);countA--;if (countA==0) V(x);V(mutexA);}
}void west_east() { while (1) {P(mutexB);countB++;if (countB==1) P(x); V(mutexB);walk across the bridge from west to east;P(mutexB);countB--;if (countB==0) V(x);V(mutexB);}
}

示例三
情境描述
  • 东西方向的独木桥,不允许停留
  • 东西方向都有人在等着过桥
  • 同一方向的行人可以连续过桥,另一方的行人必须等待
  • 桥最大可承重四人

请用P、V操作来实现东西两端行人过桥问题

分析
  • 读者优先问题
  • 行人首先上桥的一方为读者,另一方为写者,桥是数据
  • 与示例二不同在于不用一个一个过桥,只要桥没到承重限度就可以进入,这里承重限度就是临界区大小
  • 信号量
  • x:互斥信号量,互斥读者写者
  • countR:统计读者数目(同时在桥上的行人数目)
  • mutexR:对变量countR加锁
  • count: 位于独木桥上的行人数目
伪代码
int countA=0, countB=0;
semaphore x=1, muteA=1, mutexB=1,count=4;void east_west() { while (1) {P(mutexA);countA++;if (countA==1) P(x); V(mutexA);P(count);walk across the bridge from east to west;V(count);P(mutexA);countA--;if (countA==0) V(x);V(mutexA);}
}
void west_east() { while (1) {P(mutexB);countB++;if (countB==1) P(x); V(mutexB);P(count);walk across the bridge from west to east;V(count);P(mutexB);countB--;if (countB==0) V(x);V(mutexB);}
}

在这里插入图片描述


http://chatgpt.dhexx.cn/article/L3NPIoiB.shtml

相关文章

同步机制—读者写者问题

【实验目的】 理解临界区和进程互斥的概念,掌握用信号量和PV操作实现进程互斥的方法。 【实验内容】 在windows或者linux环境下编写一个控制台应用程序,该程序运行时能创建N个线程,其中既有读者线程又有写者线程,它们按照事先设计…

操作系统——读者写者问题

一、问题描述 要求: 1、允许多个读者可以同时对文件执行读操作。 2、只允许一个写者往文件中写信息。 3、任一写者在完成写操作之前不允许其他读者或写者工作。 4、写者执行写操作前,应让已有的读者和写者全部退出。 二、问题分析 读者写者问题最核心的问题是如何处理…

【操作系统-进程】PV操作——读者写者问题

文章目录 读者写者问题万能模板万能模板 1——读进程优先万能模板 2——读写公平法万能模板 3——写进程优先 题目 1:南北过桥问题题目 2:录像厅问题题目 3:更衣问题 读者写者问题万能模板 读者写者问题,其本质就是连续多个同类进…

经典进程同步问题(三)——读者写者问题

目录 一、问题描述 二、解题思路 2.1 读者优先算法 2.2 写者优先算法 2.3 读写公平 三、源码实现 3.1 读者优先 3.2 写者优先 3.3 读写平等 一、问题描述 一个数据问价或记录可以被多个进程共享,我们把只读该文件的进程称为“读者进程”,其他进…

2. 堆与栈的区别

2. 堆与栈的区别 在理解这两个概念时,需要放到具体的场景下,因为不同场景下,堆与栈代表不同的含义。一般情况下,有两层含义: (1)程序内存布局场景下,堆与栈表示的是两种内存管理方式…

栈与堆的区别(内存分配与数据结构)

参考自https://blog.csdn.net/K346K346/article/details/80849966/ 堆(Heap)与栈(Stack)包含两层含义: 程序内存布局场景下的内存管理方式数据结构中的两种常见的数据结构 1. 程序内存分配中的堆与栈 1.1 栈介绍 …

C语言里栈和堆的区别整理

这里说的是C语言程序内存分配中的堆和栈。下面先谈谈C语言的内存管理: 可执行程序在存储时(没有调到内存)分为代码区(text)、数据区(data)和未初始化数据区(bss)3个部分。…

看懂堆与栈的区别与联系

<div class"simditor-body clearfix" style"height: auto; overflow: inherit;"><h2> <strong>  堆和栈概要</strong></h2>在计算机领域&#xff0c;堆栈是一个不容忽视的概念&#xff0c;堆栈是两种数据结构。堆栈都是一…

C语言:栈和堆的区别

c语言五大内存分区 栈区&#xff08;stack&#xff09;:存放函数形参和局部变量&#xff08;auto类型&#xff09;&#xff0c;由编译器自动分配和释放 堆区&#xff08;heap&#xff09;:该区由程序员申请后使用&#xff0c;需要手动释放否则会造成内存泄漏。如果程序员没有手…

什么是栈(Stack)?什么是堆(Heap)?栈和堆的区别是什么?

原参考地址&#xff1a;https://zhidao.baidu.com/question/36918441.html 栈&#xff1a;由操作系统自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量du的值等。其操作方式类似于数据结构中的栈&#xff1b; 堆&#xff1a; 一般由程序员分配释放&#xff0c…

堆和栈的概念和区别

在说堆和栈之前&#xff0c;我们先说一下JVM&#xff08;虚拟机&#xff09;内存的划分&#xff1a; Java程序在运行时都要开辟空间&#xff0c;任何软件在运行时都要在内存中开辟空间&#xff0c;Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域&#x…

堆与栈的区别详细总结

1、堆与栈的区别详细总结_Fighting的博客-CSDN博客_堆和栈的区别 2、堆和栈的区别 - 江雨牧 - 博客园 3、堆和栈的区别_内外皆秀的博客-CSDN博客_堆和栈的区别 4、一文读懂堆与栈的区别_恋喵大鲤鱼的博客-CSDN博客_堆和栈的区别 一般情况下&#xff0c;如果有人把堆栈合起来…

栈和堆的区别

栈和堆的区别 前面已经介绍过&#xff0c;栈是由编译器在需要时分配的&#xff0c;不需要时自动清除的变量存储区。里面的变量通常是局部变量、函数参数等。堆是由malloc()函数分配的内存块&#xff0c;内存释放由程序员手动控制&#xff0c;在C语言为free函数完成。栈和堆的主…

Struts常见面试题

Struts分为Struts1和Struts2&#xff0c;默认情况下指的是Struts2&#xff0c;Struts1除非特别说明。 1、Struts2 中的 # 和 % 分别是做什么的&#xff1f; &#xff08;1&#xff09;使用#获取 context 里面的数据 <s:iterator value “list” var”user”> <s:p…

关于Struts2的笔试题(一)

一. struts2框架中struts.xml配置文件,package标签的属性有那几个?各有什么功能? 1.name属性 作用:定义一个包的名称&#xff0c;它必须唯一。 2.namespace属性 作用:主要是与action标签的name属性联合使用来确定一个action 的访问路径 3.extends属性 作用:指定继承自哪个…

Struts2详述一(struts2基础及2个核心)

临近大学毕业了&#xff0c;在毕业之前做点大学学到的知识和总结。如有哪些方面存在错误还望大神见谅。 首先&#xff0c;这里想从SSH这三大框架说起。首选从最简单的Struts2说起。这一篇我将讲述struts2一些基础及2个核心&#xff08;Action和result&#xff09;,下篇我们将着…

【面试】【Struts2常见问题总结】【02】

【常见面试问题总结目录>>>】 031 struts2如何对指定的方法进行验证&#xff1f; 1.validate()方法会校验action中所有与execute方法签名相同的方法&#xff1b;   2.要校验指定的方法通过重写validateXxx()方法实现&#xff0c; validateXxx()只会校验action中方法…

【面试】【Struts2常见问题总结】【01】

【常见面试问题总结目录>>>】 001 请简述struts1的工作流程和机制&#xff1a; Struts的工作流程:   在web应用启动时就会加载初始化ActionServlet,ActionServlet从   struts-config.xml文件中读取配置信息,把它们存放到各种配置对象   当ActionServlet接收到…

一道Struts面试题

题目是这样的 有两张表 一张为新闻类别表 有&#xff12;个字段&#xff1a; nid(pk) sort 有一张新闻内容表 有三个字段 cid(pk) nid(fk) title content 要求通过下拉列表框的方法选择新闻类别然后显示该类别的新闻标题&#xff08;在当前…

Java面试----2018年最新Struts2面试题

1、描述Struts2的工作原理 答:客户端发送请求--》请求经过一系列过滤器--》FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action --》FilterDispatcher把请求的处理交给ActionProxy--》通过ConfigurationManager询问Struts配置文件&#xff08;Struts.xml&a…