【在Linux世界中追寻伟大的One Piece】读者写者问题与读写锁
目录
1 -> 读者写者问题
1.1 -> 什么是读者写者问题
1.2 -> 读者写者与生产消费者的区别
1.3 -> 如何理解读者写者问题
2 -> 读写锁
2.1 -> 读写锁接口
3 -> 读者优先(Reader-Preference)
4 -> 写者优先(Writer-Preference)
1 -> 读者写者问题
1.1 -> 什么是读者写者问题
- 多个读者可以同时访问共享资源。例如,在一个数据库系统中,多个用户(读者)可以同时读取数据库中的某些数据,只要没有写操作在进行,这种并发读取不会导致数据的不一致性。
- 写者在对共享资源进行写操作时,必须独占资源。因为如果有多个写者同时写或者有读者在同时读取时写者进行写操作,都可能导致数据的不一致性。比如在文件系统中,一个进程(写者)在修改文件内容时,如果其他进程(读者或写者)同时操作这个文件,文件内容就可能变得混乱。
- 设计一种并发控制机制,既能保证多个读者的并发访问,又能确保写者对共享资源的独占访问,并且在写者等待访问资源时,新到达的读者不会无限期地抢占写者的访问权,以避免写者“饥饿”现象。这通常需要使用信号量等同步原语来实现。
1.2 -> 读者写者与生产消费者的区别
对比维度 | 读者写者模型 | 生产消费者模型 |
数据访问 | 读者只读,写者只写 | 生产者生产,消费者消费 |
并发访问 | 读者并行,写者互斥 | 生产者和消费者互斥 |
使用场景 | 多读少写 | 大量短时任务 |
数据处理 | 无 | 消费者处理数据 |
同步机制 | 读写锁 | 互斥锁或信号量 |
通过对比可以看出,读者写者模型更适合于数据的并发读取,而生产消费者模型更适合于数据的生产和消费。在实际应用中,应根据具体的业务需求选择合适的模型。
1.3 -> 如何理解读者写者问题
伪代码如下:
- 公共部分:
uint32_t reader_count = 0;
lock_t count_lock;
lock_t writer_lock;
- Reader
// 加锁
lock(count_lock);
if (reader_count == 0)lock(writer_lock);
++reader_count;
unlock(count_lock);// read;
//解锁
lock(count_lock);
--reader_count;
if (reader_count == 0)unlock(writer_lock);
unlock(count_lock);
- Writer
lock(writer_lock);// write
unlock(writer_lock);
2 -> 读写锁
在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢?有,那就是读写锁。
当前锁状态 | 读锁请求 | 写锁请求 |
无锁 | 可以 | 可以 |
读锁 | 可以 | 阻塞 |
写锁 | 阻塞 | 阻塞 |
注意:写独占,读共享,读锁优先级高。
2.1 -> 读写锁接口
设置读写优先
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr, int pref);
/*
pref 共有 3 种选择
PTHREAD_RWLOCK_PREFER_READER_NP (默认设置) 读者优先,可能会导致写者饥饿情况
PTHREAD_RWLOCK_PREFER_WRITER_NP 写者优先,目前有 BUG,导致表现行为和PTHREAD_RWLOCK_PREFER_READER_NP 一致
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 写者优先,但写者不能递归加锁
*/
初始化
int pthread_rwlock_init(pthread_rwlock_t* restrict rwlock, const pthread_rwlockattr_t* restrict attr);
销毁
int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);
加锁和解锁
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
读写锁案例
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <cstdlib>
#include <ctime>// 共享资源
int shared_data = 0;// 读写锁
pthread_rwlock_t rwlock;// 读者线程函数
void* Reader(void* arg)
{//sleep(1); //读者优先,一旦读者进入&&读者很多,写者基本就很难进入了int number = *(int*)arg;while (true){pthread_rwlock_rdlock(&rwlock); // 读者加锁std::cout << "读者-" << number << " 正在读取数据, 数据是: "<< shared_data << std::endl;sleep(1); // 模拟读取操作pthread_rwlock_unlock(&rwlock); // 解锁}delete (int*)arg;return NULL;
}// 写者线程函数
void* Writer(void* arg)
{int number = *(int*)arg;while (true){pthread_rwlock_wrlock(&rwlock); // 写者加锁shared_data = rand() % 100; // 修改共享数据std::cout << "写者- " << number << " 正在写入. 新的数据是: "<< shared_data << std::endl;sleep(2); // 模拟写入操作pthread_rwlock_unlock(&rwlock); // 解锁}delete (int*)arg;return NULL;
}int main()
{srand(time(nullptr) ^ getpid());pthread_rwlock_init(&rwlock, NULL); // 初始化读写锁// 可以更高读写数量配比,观察现象const int reader_num = 2;const int writer_num = 2;const int total = reader_num + writer_num;pthread_t threads[total]; // 假设读者和写者数量相等// 创建读者线程for (int i = 0; i < reader_num; ++i){int* id = new int(i);pthread_create(&threads[i], NULL, Reader, id);}// 创建写者线程for (int i = reader_num; i < total; ++i){int* id = new int(i - reader_num);pthread_create(&threads[i], NULL, Writer, id);}// 等待所有线程完成for (int i = 0; i < total; ++i){pthread_join(threads[i], NULL);}pthread_rwlock_destroy(&rwlock); // 销毁读写锁return 0;
}
Makefile
reader_writer_lock_test:reader_writer_lock_test.ccg++ -o $@ $^ -lpthread.PHONY:cleanclean:rm -f reader_writer_lock_test
部分运行效果
$ ./reader_writer_lock_test写者- 0 正在写入. 新的数据是: 82读者-0 正在读取数据, 数据是: 82写者- 0 正在写入. 新的数据是: 32读者-0 正在读取数据, 数据是: 32写者- 0 正在写入. 新的数据是: 30读者-0 正在读取数据, 数据是: 30写者- 0 正在写入. 新的数据是: 27读者-0 正在读取数据, 数据是: 27写者- 0 正在写入. 新的数据是: 43读者-0 正在读取数据, 数据是: 43写者- 0 正在写入. 新的数据是: 47
3 -> 读者优先(Reader-Preference)
在这种策略中,系统会尽可能多地允许多个读者同时访问资源(比如共享文件或数据),而不会优先考虑写者。这意味着当有读者正在读取时,新到达的读者会立即被允许进入读取区,而写者则会被阻塞,直到所有读者都离开读取区。读者优先策略可能会导致写者饥饿(即写者长时间无法获得写入权限),特别是当读者频繁到达时。
4 -> 写者优先(Writer-Preference)
在这种策略中,系统会优先考虑写者。当写者请求写入权限时,系统会尽快地让写者进入写入区,即使此时有读者正在读取。这通常意味着一旦有写者到达,所有后续的读者都会被阻塞,直到写者完成写入并离开写入区。写者优先策略可以减少写者等待的时间,但可能会导致读者饥饿(即读者长时间无法获得读取权限),特别是当写者频繁到达时。
感谢各位大佬支持!!!
互三啦!!!
相关文章:

【在Linux世界中追寻伟大的One Piece】读者写者问题与读写锁
目录 1 -> 读者写者问题 1.1 -> 什么是读者写者问题 1.2 -> 读者写者与生产消费者的区别 1.3 -> 如何理解读者写者问题 2 -> 读写锁 2.1 -> 读写锁接口 3 -> 读者优先(Reader-Preference) 4 -> 写者优先(Writer-Preference) 1 -> 读者写者…...

用到动态库的程序运行过程
当我们写好了一段代码然后编译运行后会生成可执行文件,该文件会存在磁盘的当前目录下,而当我们开始运行这段程序时,操作系统(加载器)需要将其从磁盘加载进内存然后执行相关操作,而对于用到动态库的程序&…...

类型转换与IO流:C++世界的变形与交互之道
文章目录 前言🎄一、类型转换🎈1.1 隐式类型转换🎈1.2 显式类型转换🎁1. C 风格强制类型转换🎁2. C 类型转换操作符 🎈1.3 C 类型转换操作符详解🎁1. static_cast🎁2. dynamic_cast&…...
Pytorch使用手册- TorchVision目标检测微调Tutorial的使用指南(专题十二)
这篇教程的目标是对一个预训练的 Mask R-CNN 模型进行微调,应用于 Penn-Fudan 行人检测与分割数据集。该数据集包含 170 张图像,里面有 345 个行人实例,我们将通过这个教程来演示如何使用 torchvision 中的新特性,训练一个面向自定义数据集的目标检测和实例分割模型。 注意…...
人工智能机器学习算法分类全解析
目录 一、引言 二、机器学习算法分类概述 (一)基于学习方式的分类 1. 监督学习(Supervised Learning) 2. 无监督学习(Unsupervised Learning) 3. 强化学习(Reinforcement Learning…...
Linux 35.6 + JetPack v5.1.4@DeepStream安装
Linux 35.6 JetPack v5.1.4DeepStream安装 1. 源由2. 步骤Step 1 安装Jetpack 5.1.4 L4T 35.6Step 2 安装依赖组件Step 3 安装librdkafkaStep 4 安装 DeepStream SDKStep 5 测试 deepstream-appStep 6 运行 deepstream-app 3. 总结3.1 版本问题3.2 二进制help 4. 参考资料 1. …...

图数据库 | 11、图数据库架构设计——高性能图存储架构(下)
在上篇内容中,老夫着重讲了高性能图存储系统的特点,咱们继续往下讲重点——高性能存储架构的设计思路!! 2.高性能存储架构设计思路 首先呢,存储架构以及核心数据结构的设计思路通常围绕如下4个维度来进行:…...

【HTTP】HTTP协议
一个Web Server就是个服务器软件(程序),或者是运行这个服务器软件的硬件(计算机),其主要功能是通过HTTP协议与客户端进行通信,来接收,存储,处理来自客户端的HTTP请求&…...

大数据新视界 -- Hive 基于 MapReduce 的执行原理(上)(23 / 30)
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

SpringBoot源码解析(六):打印Banner
SpringBoot源码系列文章 SpringBoot源码解析(一):SpringApplication构造方法 SpringBoot源码解析(二):引导上下文DefaultBootstrapContext SpringBoot源码解析(三):启动开始阶段 SpringBoot源码解析(四):解析应用参数args Sp…...

【计算机网络】实验6:IPV4地址的构造超网及IP数据报
实验 6:IPV4地址的构造超网及IP数据报 一、 实验目的 加深对IPV4地址的构造超网(无分类编制)的了解。 加深对IP数据包的发送和转发流程的了解。 二、 实验环境 • Cisco Packet Tracer 模拟器 三、 实验内容 1、了解IPV4地址的构造超网…...
easy excel 生成excel 文件
导包 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.3</version> </dependency> 内容 List<类> limspjreport 值; String fileName sdf.format(new Date()) "-…...

Ajax:回忆与节点
一点回忆 面对我的Ajax学习,实现前后端交互,最开始我采用的使用网络寻找intellij IDEA Ultimate破解方法,然后最终成功,然后按照相关教程配置java ee项目,然后中间又去配置了Tomcat服务器,然后又去学习了一…...
Python+OpenCV系列:Python和OpenCV的结合和发展
PythonOpenCV系列:Python和OpenCV的结合和发展 **引言****Python语言的发展****1.1 Python的诞生与发展****1.2 Python的核心特性与优势****1.3 Python的应用领域** **OpenCV的发展****2.1 OpenCV的起源与发展****2.2 OpenCV的功能特性****2.3 OpenCV的应用场景** *…...

Ubuntu20.04 由源码编译安装opencv3.2 OpenCV
Ubuntu20.04 由源码编译安装opencv3.2.0 获取 opencv 及opencv_contrib源代码 创建目录以存放opencv及opencv_contrib源代码 mkdir ~/opencv3.2.0 cd ~/opencv3.2.0获取opencv源代码并切换到对应tag git clone https://github.com/opencv/opencv.git cd opencv git checkou…...

A058-基于Spring Boot的餐饮管理系统的设计与实现
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看项目链接获取⬇️,记得注明来意哦~🌹 赠送计算机毕业设计600个选题ex…...

RDIFramework.NET CS敏捷开发框架 SOA服务三种访问(直连、WCF、WebAPI)方式
1、介绍 在软件开发领域,尤其是企业级应用开发中,灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目,如何高效地与后端数据库进行交互,以及如何提供多样化的服务访问方式,是开发者需要深入考虑的问题。…...

Linux——命名管道及日志
linux——进程间通信及管道的应用场景-CSDN博客 文章目录 目录 文章目录 前言 一、命名管道是什么? 理解: 2、编写代码 makefile 管道封装成类,想用中管道时只需要调用实例化 读端 写端 日志 1、日志是什么? 2、日志有什么&#x…...
Flink 常见面试题
1、Flink 的四大特征(基石) checkpoin基于Chandy-Lamport算法实现了分布式一致性快照提供了一致性的语义 state丰富的StateAPI time实现了Watermark机制,乱序数据处理,迟到数据容忍 window开箱即用的滚动,滑动会话窗口…...

rtc-pcf8563 0-0051: low voltage detected, date/time is not reliable
解决方法: 1、先测量pcf8563电源电压,是否满足要求。 2、pcf8563首次操作。第一次读取pcf8563的时间,未初始化,非法,芯片门槛电压检测配置不合理。使用hwclock命令写入一次,即可解决。 hwclock -f /dev/…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...