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

【在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.cc
g++ -o $@ $^ -lpthread
.PHONY:clean
clean:
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 -> 读者写者…...

用到动态库的程序运行过程

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

类型转换与IO流:C++世界的变形与交互之道

文章目录 前言&#x1f384;一、类型转换&#x1f388;1.1 隐式类型转换&#x1f388;1.2 显式类型转换&#x1f381;1. C 风格强制类型转换&#x1f381;2. C 类型转换操作符 &#x1f388;1.3 C 类型转换操作符详解&#x1f381;1. static_cast&#x1f381;2. dynamic_cast&…...

Pytorch使用手册- TorchVision目标检测微调Tutorial的使用指南(专题十二)

这篇教程的目标是对一个预训练的 Mask R-CNN 模型进行微调,应用于 Penn-Fudan 行人检测与分割数据集。该数据集包含 170 张图像,里面有 345 个行人实例,我们将通过这个教程来演示如何使用 torchvision 中的新特性,训练一个面向自定义数据集的目标检测和实例分割模型。 注意…...

人工智能机器学习算法分类全解析

目录 一、引言 二、机器学习算法分类概述 &#xff08;一&#xff09;基于学习方式的分类 1. 监督学习&#xff08;Supervised Learning&#xff09; 2. 无监督学习&#xff08;Unsupervised Learning&#xff09; 3. 强化学习&#xff08;Reinforcement Learning&#xf…...

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、图数据库架构设计——高性能图存储架构(下)

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

【HTTP】HTTP协议

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

大数据新视界 -- Hive 基于 MapReduce 的执行原理(上)(23 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

SpringBoot源码解析(六):打印Banner

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

【计算机网络】实验6:IPV4地址的构造超网及IP数据报

实验 6&#xff1a;IPV4地址的构造超网及IP数据报 一、 实验目的 加深对IPV4地址的构造超网&#xff08;无分类编制&#xff09;的了解。 加深对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学习&#xff0c;实现前后端交互&#xff0c;最开始我采用的使用网络寻找intellij IDEA Ultimate破解方法&#xff0c;然后最终成功&#xff0c;然后按照相关教程配置java ee项目&#xff0c;然后中间又去配置了Tomcat服务器&#xff0c;然后又去学习了一…...

Python+OpenCV系列:Python和OpenCV的结合和发展

PythonOpenCV系列&#xff1a;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的餐饮管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看项目链接获取⬇️&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600个选题ex…...

RDIFramework.NET CS敏捷开发框架 SOA服务三种访问(直连、WCF、WebAPI)方式

1、介绍 在软件开发领域&#xff0c;尤其是企业级应用开发中&#xff0c;灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目&#xff0c;如何高效地与后端数据库进行交互&#xff0c;以及如何提供多样化的服务访问方式&#xff0c;是开发者需要深入考虑的问题。…...

Linux——命名管道及日志

linux——进程间通信及管道的应用场景-CSDN博客 文章目录 目录 文章目录 前言 一、命名管道是什么&#xff1f; 理解&#xff1a; 2、编写代码 makefile 管道封装成类&#xff0c;想用中管道时只需要调用实例化 读端 写端 日志 1、日志是什么&#xff1f; 2、日志有什么&#x…...

Flink 常见面试题

1、Flink 的四大特征&#xff08;基石&#xff09; checkpoin基于Chandy-Lamport算法实现了分布式一致性快照提供了一致性的语义 state丰富的StateAPI time实现了Watermark机制&#xff0c;乱序数据处理&#xff0c;迟到数据容忍 window开箱即用的滚动&#xff0c;滑动会话窗口…...

rtc-pcf8563 0-0051: low voltage detected, date/time is not reliable

解决方法&#xff1a; 1、先测量pcf8563电源电压&#xff0c;是否满足要求。 2、pcf8563首次操作。第一次读取pcf8563的时间&#xff0c;未初始化&#xff0c;非法&#xff0c;芯片门槛电压检测配置不合理。使用hwclock命令写入一次&#xff0c;即可解决。 hwclock -f /dev/…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...