【操作系统】读者—写者问题python解析
一个数据问价或记录可以被多个进程共享,我们把只读该文件的进程称为“读者进程”,其他进程为“写者进程”。允许多个进程同时读一个共享对象,但不允许一个写者进程和其他写者进程或读者进程同时访问共享对象。即:保证一个写者进程必须与其他进程互斥的访问共享对象的同步问题;读者-写者问题常用来测试新同步原语。
1、问题解答思路
利用了锁和信号量进行同步,以确保读者和写者之间不会相互干扰地访问缓冲区。读者可以同时访问缓冲区,但写者必须具有排他性访问。ReaderWriter类包含了共享缓冲区、活跃读者数量、写入状态标志以及用于互斥访问和信号量的锁和信号量。read函数实现读者的行为。读者先获取read_sem信号量,然后获取锁,增加活跃读者数量,如果是第一个读者,就获取write_sem信号量以防止写者进入。读取缓冲区内容后,减少活跃读者数量,并在没有活跃读者时释放`write_sem`信号量。write函数实现写者的行为。写者首先获取write_sem信号量,然后获取锁,设置写入状态标志为True。写入数据到缓冲区后,释放锁并设置写入状态标志为False,最后释放write_sem信号量。最后创建了多个读者和写者线程,并启动它们。然后等待所有线程结束。
2、问题流程图
graph TD;
A[开始] --> B[初始化ReaderWriter对象];
B --> C[创建多个读者和写者线程];
C --> D[启动所有线程];
D --> E[等待所有线程结束];
E --> F[结束];
3、源码
import threading
import time
import randomclass ReaderWriter:def __init__(self):self.buffer = [] #共享缓冲区self.readers = 0 #活跃读者数量self.writing = False #写入状态标志self.lock = threading.Lock() #互斥访问锁self.read_sem = threading.Semaphore(1)self.write_sem = threading.Semaphore(1) #信号量def read(self, reader_id):while True:self.read_sem.acquire()self.lock.acquire()self.readers += 1if self.readers == 1:self.write_sem.acquire()self.lock.release()self.read_sem.release()print(f"读者 {reader_id} 正在读: {self.buffer}")self.lock.acquire()self.readers -= 1if self.readers == 0:self.write_sem.release()self.lock.release()time.sleep(random.random())def write(self, writer_id):while True:self.write_sem.acquire()self.lock.acquire()self.writing = Trueself.lock.release()data = random.randint(1, 100)self.buffer.append(data)print(f"写者 {writer_id} 正在写: {data}")self.lock.acquire()self.writing = Falseself.write_sem.release()self.lock.release()time.sleep(random.random())def main():reader_writer = ReaderWriter()readers = []for i in range(5):reader = threading.Thread(target=reader_writer.read, args=(i,))readers.append(reader)writers = []for i in range(2):writer = threading.Thread(target=reader_writer.write, args=(i,))writers.append(writer)for reader in readers:reader.start()for writer in writers:writer.start()for reader in readers:reader.join()for writer in writers:writer.join()if __name__ == "__main__":main()
4、输出
读者 0 正在读: []
读者 1 正在读: []
读者 2 正在读: []
读者 3 正在读: []
读者 4 正在读: []
写者 0 正在写: 36
写者 1 正在写: 61
读者 1 正在读: [36, 61]
写者 0 正在写: 61
读者 1 正在读: [36, 61, 61]
写者 0 正在写: 85
读者 0 正在读: [36, 61, 61, 85]
写者 1 正在写: 69
读者 4 正在读: [36, 61, 61, 85, 69]
读者 1 正在读: [36, 61, 61, 85, 69]
读者 3 正在读: [36, 61, 61, 85, 69]
读者 2 正在读: [36, 61, 61, 85, 69]
读者 3 正在读: [36, 61, 61, 85, 69]
写者 0 正在写: 11
读者 0 正在读: [36, 61, 61, 85, 69, 11]
读者 4 正在读: [36, 61, 61, 85, 69, 11]
读者 2 正在读: [36, 61, 61, 85, 69, 11]
读者 1 正在读: [36, 61, 61, 85, 69, 11]
写者 1 正在写: 61
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61]
写者 1 正在写: 61
读者 3 正在读: [36, 61, 61, 85, 69, 11, 61, 61]
读者 2 正在读: [36, 61, 61, 85, 69, 11, 61, 61]
写者 1 正在写: 19
读者 1 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19]
写者 1 正在写: 77
写者 1 正在写: 3
读者 4 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3]
写者 0 正在写: 79
读者 4 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79]
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79]
读者 3 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79]
读者 1 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79]
读者 2 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79]
写者 1 正在写: 32
写者 1 正在写: 17
写者 0 正在写: 53
读者 1 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
读者 2 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
读者 4 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
读者 3 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
读者 4 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53]
写者 0 正在写: 89
写者 1 正在写: 92
读者 1 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92]
读者 3 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92]
读者 2 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92]
读者 2 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92]
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92]
写者 0 正在写: 28
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92, 28]
读者 0 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92, 28]
写者 1 正在写: 68
读者 4 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92, 28, 68]
读者 3 正在读: [36, 61, 61, 85, 69, 11, 61, 61, 19, 77, 3, 79, 32, 17, 53, 89, 92, 28, 68]
写者 0 正在写: 66进程已结束,退出代码-1
相关文章:
【操作系统】读者—写者问题python解析
一个数据问价或记录可以被多个进程共享,我们把只读该文件的进程称为“读者进程”,其他进程为“写者进程”。允许多个进程同时读一个共享对象,但不允许一个写者进程和其他写者进程或读者进程同时访问共享对象。即:保证一个写者进程…...

【driver5】调用堆栈函数,printk,动态打印,ftrace,proc,sysfs
文章目录 1.内核函数调用堆栈:4个函数2.printk:cat /proc/cmdline查看consolettyS03.动态打印:printk是全局的且只能设打印等级,动态打印可控制选择模块的打印,在内核配置打开CONFIG_DYNAMIC_DEBUG4.top&perf&…...

计算机毕业设计springboot基于vue电商抢购限时秒杀系统ch0h8
技术栈 ide工具:IDEA 或者eclipse 编程语言: java 数据库: mysql5.7以上版本 可选框架:ssmspringboot都有的 前端:vue.jsElementUI 详细技术:springbootSSMvueMYSQLMAVEN 数据库工具:Navicat/SQLyog都可以 开发工具 Ec…...

顺序表的实现(迈入数据结构的大门)(2)
目录 顺序表的头插(SLPushFront) 此时:我们有两个思路(数组移位) 顺序表的头删(学会思维的变换)(SLPopFront) 顺序表的尾插(SLPushBack) 有尾插就有尾删 既然头与尾部的插入与删除都有,那必然少不了指定位置的插入删除 查找…...
学习笔记:IEEE 1003.13-2003【POSIX PSE51接口列表】
一、POSIX PSE51接口列表 根据IEEE 1003.13-2003,整理了POSIX PSE51接口API(一共286个),每个API支持链接查看。详细内容参考下面表格: SN Module/_POSIX_宏 Function File 1 POSIX_C_LANG_JUMP(2) longjmp() &…...

《QT实用小工具·五十》动态增删数据与平滑缩放移动的折线图
1、概述 源码放在文章末尾 该项目实现了带动画、带交互的折线图,包含如下特点: 动态增删数值 自适应显示坐标轴数值 鼠标悬浮显示十字对准线 鼠标靠近点自动贴附 支持直线与平滑曲线效果 自定义点的显示类型与大小 自适应点的数值显示位置 根据指定锚点…...

【qt】核心机制信号槽(下)
这里写目录标题 自定义的信号自定义的槽自定义的信号和槽的结合使用信号和槽的断开总结: 自定义的信号 信号就是一个函数声明 前面咱们都用的qt组件自带的信号,接下来我们自己写一个信号。 信号只需要在前面加一个signals即可 这个函数不需要实现 参数传…...

C++ 基础 输入输出
一 C 的基本IO 系统中的预定义流对象cin和cout: 输入流:cin处理标准输入,即键盘输入; 输出流:cout处理标准输出,即屏幕输出; 流:从某种IO设备上读入或写出的字符系列 使用cin、cout这两个流对…...

八股文(C#篇)
C#中的数值类型 堆和栈 值类型的数据被保存在栈(stack)上,而引用类型的数据被保存在堆(heap)上,当值类型作为参数传递给函数时,会将其复制到新的内存空间中,因此在函数中对该值类型的修改不会影…...
【YOLOv9算法原理简介】
YOLOv9算法原理 单阶段检测器:YOLOv9延续了YOLO系列的单阶段检测器设计,即在单次前向传播中同时预测边界框和类别概率,这使得它能够实现快速的检测速度。通用高效层聚合网络(GELAN) :YOLOv9引入了一种新的模型架构GELAN,它通过高效的层聚合块和计算模块,以较小的参数量…...

2010NOIP普及组真题 2. 接水问题
线上OJ: 一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid1950 解法一、朴素模拟 核心思想: 朴素模拟: 1、先给每个b[i]水龙头分配一个人a[i],b[i] 表示水龙头的剩余时间。同时标记该水龙头为 used 使用中 2…...

ElementUI从unpkg.com完整下载到本地的方法 - 解决unpkg.com不稳定的问题 - 自建镜像站 - 不想打包只想cdn一下
方法 方法1)随便弄个文件夹,根据官网npm方法下载包,提取即可 npm i element-ui -S cd /node_modules/element-ui/ ls src 安装npm方法:https://nodejs.org/en 方法2)不推荐 - 在github中搜索对应的库zip包࿰…...
什么是BFF API
BFF(Backend For Frontend)API 是一种架构模式,旨在为特定的前端应用(如移动应用、桌面应用或网页应用)提供定制化的后端服务。通过这种方式,后端可以根据前端的具体需求和特性,提供最优化的数据…...

分享自己一篇在亚马逊云科技AWS官网发的Blog技术文章
小李哥在亚马逊AWS官网,作为第一作者发了自己的第一篇AWS Blog文章,也是自己今年在AWS官网的第11篇文章。文章主要内容是描述为出海的金融企业,搭建满足PCI-DSS合规、FIPS 140-2 Level 3安全标准的传输中数据加密云端方案,主要用于…...
封装长按触发事件的uniapp组件
简单说一下原理 首先介绍三个针对触摸屏设备的事件,分别是: touchstart:当手指触摸屏幕时触发,即触摸开始的时候;touchend:当手指离开屏幕时触发,即触摸结束的时候;touchcancel&am…...

Docker 安装的MySQL迁移数据库
1. 导出数据库 docker ps :查看数据库对应的 CONTAINER ID docker exec -it id /bin/bash : 进入到mysql的docker实例中 cd /usr/bin : 进入到bin目录 mysqldump -u root -p123456 study > /root/study_backup0509.sql :使用mysqldump备份库,注意密码与-p之间…...
算法训练Day28 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II
122.买卖股票的最佳时机II class Solution { public:int maxProfit(vector<int>& prices) {vector<int> dp(2,0);dp[0] -prices[0];for(int i1; i<prices.size(); i){dp[0] max(dp[0], dp[1]-prices[i]);dp[1] max(dp[1], prices[i]dp[0]);}return dp[1]…...

Linux(openEuler、CentOS8)基于chrony企业内网NTP服务器搭建实验
一、知识点 chrony 是由 守护进程 chronyd 以及 命令行工具 chronyc 组成的 chronyd 在后台静默运行并通过 123 端口与时间服务器定时同步时间,默认的配置文件是 /etc/chrony.conf chronyc 通过 323 端口与 chronyd 交互,可监控 chronyd 的性能并在运…...

前端开发框架Vue
版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl Vue概述 Vue.js(简称Vue)是由尤雨溪(Evan You)创建并维护的一款开源前端开发框架。Vue以其轻量级、易上手和高度灵活的特点&…...
Vue2中引入ElementUI
Vue中引入ElementUI 目录 Vue中引入ElementUI安装 全库导入main.py使用 仅引入样式文件main.py使用 安装 官方文档 npm i element-ui -S全库导入 main.py import ElementUI from element-ui;Vue.use(ElementUI)使用 <template> <div class"main">&l…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...