当前位置: 首页 > news >正文

【操作系统】读者—写者问题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包&#xff0…...

什么是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 端口与时间服务器定时同步时间&#xff0c;默认的配置文件是 /etc/chrony.conf chronyc 通过 323 端口与 chronyd 交互&#xff0c;可监控 chronyd 的性能并在运…...

前端开发框架Vue

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Vue概述 Vue.js&#xff08;简称Vue&#xff09;是由尤雨溪&#xff08;Evan You&#xff09;创建并维护的一款开源前端开发框架。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…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...