四、操作系统——读者写者问题(详解)

article/2025/9/30 8:15:36

一、问题描述:

在这里插入图片描述

二、需要满足的条件:

  1. 写进程与写进程之间必须互斥的写入数据(因为如果两个写进程同时对共享数据中的区域A中的数据进行写操作的话,会导致数据错误覆盖的问题
  2. 写进程与读进程之间必须互斥的访问共享数据(因为写进程与读进程如果同时访问共享数据,可能会导致数据不一致的问题。比如:读进程A想要访问共享数据中的B数据,但是写进程C在读进程A访问B数据之前将B数据进行了更新,这就会导致读进程A读不到它想要读到的数据,从而出现数据不一致问题
  3. 读进程与读进程之间可以同时访问数据,不需要实现互斥的访问共享数据(因为读进程读数据,并不会像之前的生产者消费者问题中的消费者那样改变数据或者是将数据清空,所以多个读进程可以同时访问共享数据)

三、解题思路:

  1. 第一步解决写进程与写进程之间必须互斥的写入数据写进程与读进程之间必须互斥的访问共享数据 两个问题。

在这里插入图片描述

上面这种实现方式确实解决了了写进程与写进程之间必须互斥的写入数据写进程与读进程之间必须互斥的访问共享数据 这两个问题。但是,
假设读进程A正在访问共享数据,执行了P(rw) 和 读数据操作,还没有执行V操作解锁,此时读进程B也想访问共享数据,此时,读进程B会卡在P(rw)中的循环里面,也就是说进程B被阻塞了。
读进程与读进程之间也变成了必须互斥访问共享数据,并不满足题目读进程与读进程可以同时访问共享数据的要求

  1. 下面来实现多个读进程可以同时访问共享数据
    解决方法:
    引入count变量,用来记录当前有几个读进程在访问共享数据。

在这里插入图片描述

  1. 上述实现方法表面上看达到了实现多个读进程可以同时访问共享数据的目的,但其实还是存在问题的。
    存在的问题:
    如果读进程A想要访问共享数据,并且执行了P(rw)“上锁”操作,此时,读进程B也想要访问共享数据,也会执行P(rw),但是因为进程A已经执行了“上锁”操作,所以进程B还是会被阻塞,无法访问共享数据。可见,仍然没有达到多个读进程可以同时访问共享数据的目的!
    出现这种问题的原因:
    对于count变量的检查与赋值操作无法“一气呵成”,可以被中断。
    解决方法:
    可以增加一个mutex互斥信号量来保证if判断语句 和 count++(count–) 能够“一气呵成”执行完,中间不会被打断,保证各进程对count的访问是互斥的
    在这里插入图片描述
    在这里插入图片描述

  2. 上述解决方案确实已经达到了多个读进程可以同时访问共享数据的目的,但此时,又出现了新的问题:只要又读进程在读取共享数据,写进程就要一直阻塞等待,这很可能导致写进程一直无法往共享数据中写入数据,也就是说写进程很有可能会被“饿死”。因此,这种算法中,读进程是优先的!下面我们来解决写进程可能会被“饿死”这个问题
    解决方法:
    设置变量semaphore w =1 ,用于实现“写优先”。然后分别为读进程、写进程增加关于信号变量w的P、V操作。
    在这里插入图片描述
    在这里插入图片描述
    经过上面的“改造”,我们来验证一下是否达到了“写优先”的目的:
    读进程A——>写进程a——>读进程B:
    假设读进程A正在访问共享数据,那么读进程A肯定已经执行了P(w)、P(mutex)、P(rw)、V(mutex)、V(w)。此时,写进程a也想要访问共享数据,那么当读进程a执行P(w)时,不会被阻塞,但是执行到P(rw)时,由于读进程A还没有执行V(rw)“解锁”操作,所以,写进程a会被阻塞等待
    而如果此时有第二个读进程B也想要访问共享数据,但由于之前第一个读进程A已经执行了P(w)“上锁”操作,所以当读进程B执行到P(w)操作时,也会被堵塞等待
    直到读进程A完成了读文件操作后,执行了V(rw)“解锁”操作,写进程a才会被“唤醒”。然后在写进程完成了写文件操作后,执行了V(w)“解锁”操作,读进程B才能被唤醒
    注意:这里为什么会先唤醒写进程a呢?
    答:因为这里是写进程a比读进程B先想要访问共享数据,所以优先被唤醒。这里其实就是“先来先服务算法

结论:
在这种算法中,连续进入的多个读进程,可以同时读文件;写进程和其他进程不能同时访问文件;写进程不会“饥饿”。但也并不是真正的“写优先”,而是遵循相对公平的先来先服务原则。有的也称这种算法为“读写公平法”。

四、总结:

读者-写者问题为我们解决复杂的互斥问题提供了一个参考思路:
核心思想在于设置了一个计数器count用来记录当前正在访问共享文件的读进程数。我们可以用count的值来判断当前进入的进程是否是第一个/最后一个读进程,从而做出不同的处理。如果是第一个进程则执行“上锁”操作,如果是最后一个进程则执行“解锁”操作。
另外,对count变量的检查和赋值不能一气呵成导致了一些错误,如果需要实现“一气呵成”,自然应该想到用互斥信号量
最后,还要认真体会我们是如何解决“写进程饥饿”问题的。
绝大多数的PV操作大题都可以用之前介绍的几种生产者-消费者问题的思想来解决,如果遇到更复杂的问题,可以想想能否用读者写者问题的这几个思想来解决。


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

相关文章

锁机制:读者写者问题 Linux C

最近碰到一些锁机制的问题,想起大三的时候做过的一个小课设,记录复习一下。 问题描述: 一个数据文件可以被多个进程共享,其中,有些进程要求读(reader进程),而另一些进程要求对数据…

写优先的读者写者问题(Java实现)

该题系吉林大学19级软件学院操作系统课设题之一 先输入初始时的写者读者情况,优先级顺序做了随机处理 代码如下 GUI: import javax.swing.*; import javax.swing.border.Border; import javax.swing.text.BadLocationException; import javax.swing.tex…

操作系统读者写者问题代码实现

问题分析: 读者优先: 读者进程执行: 无其他读者写者, 直接执行有写者等, 但其他读者在读, 直接读有写者写, 等待写者进程执行: 无其他读写者, 直接执行有其他读写者, 等待 写者优先: 读者进程执行: 如果此时没有写者等待, 直接执行如果有写者等待, 那么等待写者…

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

2.16 读者写者问题 抽象解释 多个进程访问一个共享的数据区读者(读进程)只能读数据,写者(写进程)只能写数据适用于数据库、文件、内存、寄存器等数据区的访问模型如12306购票系统,由于用户量庞大和数据量…

同步机制—读者写者问题

【实验目的】 理解临界区和进程互斥的概念,掌握用信号量和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;,下篇我们将着…