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

Linux 读者写者模型

1.背景概念

在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。这样就衍生出了读者写者模型,在这个模型中,有两类线程:读者和写者。读者线程读取共享资源,而写者线程则修改共享资源,读者和读者之间为共享关系,写者和写者为同步互斥关系,读者和写者之间为互斥关系。
该模型有两种策略:

读者优先策略

在读者优先策略中,允许多个读者同时访问共享资源,有读者在读时,写者必须等待,直到所有当前的读者和写者都完成访问。这种策略可以提高并发度,但可能导致写者饥饿。

写者优先策略

在写者优先策略中,一旦有写者等待,新的读者必须等待,直到所有当前的读者和写者都完成访问。这种策略可以减少写者的等待时间,但可能导致读者饥饿。

通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 在Linux系统中,可以使用信号量(Semaphore)或读写锁(Read-Write Lock)来解决读者写者问题。信号量可以用来实现互斥访问,而读写锁则可以允许多个读者同时访问,但在有写者等待时,新的读者必须等待,接下来我们介绍读写锁。

2.读写锁

  • 读模式(共享模式)
    • 多个线程可以同时以读模式持有读写锁。当一个线程以读模式获取到读写锁后,其他线程如果也想要以读模式获取该锁,是可以成功获取的。这是因为多个读操作通常不会相互干扰,不会破坏数据的一致性。例如,多个线程同时读取一个共享文件的内容,它们可以同时进行,不会有冲突。
  • 写模式(独占模式)
    • 只有一个线程可以以写模式持有读写锁。当一个线程以写模式获取到读写锁时,其他任何线程(无论是想要以读模式还是写模式获取该锁)都必须等待。这是因为写操作会修改共享资源,如果有其他线程同时进行读或写操作,可能会导致数据不一致。例如,当一个线程正在修改一个共享文件时,不允许其他线程同时读取或修改该文件。

在Linux中,读写锁的类型为 pthread_rwlock_t,其使用方法与互斥锁基本一致。

读写锁的创建

1. 可以使用PTHREAD_RWLOCK_INITIALIZER初始化创建全局的读写锁,并且无需销毁。

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
2. 使用 pthread_rwlock_init 函数初始化读写锁。
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);

参数:

  • rwlock:指向要初始化的读写锁对象的指针。
  • attr:指向读写锁属性对象的指针,如果不需要特殊属性,可以设置为 NULL,使用默认属性。

函数成功时返回 0;失败时返回错误码。

加锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_rdlock 用于给读写锁申请一个读锁。如果读写锁当前没有被写锁占用,那么调用线程可以立即获得读锁。如果读写锁当前被写锁占用,那么调用线程将被阻塞,直到写锁被释放。

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

pthread_rwlock_wrlock 用于给读写锁申请一个写锁。如果读写锁当前没有被任何锁占用,那么调用线程可以立即获得写锁。如果读写锁当前被读锁或写锁占用,那么调用线程将被阻塞,直到所有的读锁和写锁都被释放。

rwlock:指向要申请读锁的读写锁对象的指针。

解锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

pthread_rwlock_unlock 函数用于释放之前通过 pthread_rwlock_rdlock(读锁)或者 pthread_rwlock_wrlock(写锁)获取的读写锁。

读写锁的销毁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

3.基于读写锁实现的读者写者模型

基于读写锁,我们来实现一个测试代码看看效果

#include <iostream>
#include <pthread.h>
#include <string>
#include <unistd.h>
using namespace std;
int g_tickets = 100;
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; // 读写锁
struct ThreadData
{pthread_t tid;string name;
};
void *ReaderRoutinue(void *arg)
{ThreadData *reader = static_cast<ThreadData *>(arg);while (true){usleep(1000);pthread_rwlock_rdlock(&rwlock); // 读锁if (g_tickets > 0)cout << reader->name << " check a ticket-" << g_tickets << endl;else{pthread_rwlock_unlock(&rwlock);break;}pthread_rwlock_unlock(&rwlock);}return nullptr;
}
void *WriterRoutinue(void *arg)
{ThreadData *writer = static_cast<ThreadData *>(arg);while (true){usleep(2000);pthread_rwlock_wrlock(&rwlock); // 写锁if (g_tickets > 0)cout << writer->name << " get a ticket-" << g_tickets-- << endl;else{pthread_rwlock_unlock(&rwlock);break;}pthread_rwlock_unlock(&rwlock);}return nullptr;
}
int main()
{ThreadData readers[5];ThreadData writers[2];for (int i = 0; i < 5; i++){readers[i].name = "Reader-" + to_string(i + 1);pthread_create(&readers[i].tid, nullptr, ReaderRoutinue, &readers[i]);}for (int i = 0; i < 2; i++){writers[i].name = "Writer-" + to_string(i + 1);pthread_create(&writers[i].tid, nullptr, WriterRoutinue, &writers[i]);}for (int i = 0; i < 5; i++)pthread_join(readers[i].tid, nullptr);for (int i = 0; i < 2; i++)pthread_join(writers[i].tid, nullptr);return 0;
}

相关文章:

Linux 读者写者模型

1.背景概念 在编写多线程的时候&#xff0c;有一种情况是十分常见的。那就是&#xff0c;有些公共数据修改的机会比较少。相比较改写&#xff0c;它们读的机会反而高的多。这样就衍生出了读者写者模型&#xff0c;在这个模型中&#xff0c;有两类线程&#xff1a;读者和写者。读…...

JavaScript 的 axios 实现文件下载功能

用 JavaScript 的 axios 实现文件下载功能&#xff0c;咱们要分几个步骤来搞定它&#xff01;最主要的部分是处理 二进制数据&#xff0c;可以生成一个进度检测&#xff0c;然后把它保存为文件。 文件名的获取二进制数据获取创建下载链接 const axios require(axios);const g…...

合合信息亮相2024中国模式识别与计算机视觉大会,用AI构建图像内容安全防线

近日&#xff0c;第七届中国模式识别与计算机视觉大会&#xff08;简称“PRCV 2024”&#xff09;在乌鲁木齐举办。大会由中国自动化学会&#xff08;CAA&#xff09;、中国图象图形学学会&#xff08;CSIG&#xff09;、中国人工智能学会&#xff08;CAAI&#xff09;和中国计…...

深度学习:匿名函数lambda函数的使用与numerical_gradient函数

背景&#xff1a; 假设我们有一个简单的线性回归模型&#xff0c;其损失函数是均方误差&#xff08;MSE&#xff09;&#xff1a; class LinearModel:def __init__(self):self.W np.random.randn(1, 1) # 初始化权重def predict(self, x):return np.dot(x, self.W) # 线性预…...

PHP数据类型

几种常用的数据类型&#xff1a; String&#xff08;字符串&#xff09; Integer&#xff08;整型&#xff09; Float&#xff08;浮点型&#xff09; Boolean&#xff08;布尔型&#xff09; NULL&#xff08;空值&#xff09; Array&#xff08;数组&#xff09; Obje…...

2FA-双因素认证

双因素认证&#xff08;2FA&#xff0c;Two-Factor Authentication&#xff09;是一种提高安全性的方法&#xff0c;要求用户在登录或进行某些敏感操作时提供两种不同类型的身份验证信息。这种方法通过引入第二层验证&#xff0c;增加了账户被未经授权访问的难度。 项目结构 …...

解决 Python 中的 TypeError 错误

解决 Python 中的 TypeError 错误 在 Python 编程中&#xff0c;TypeError 是一种常见的错误&#xff0c;通常发生在尝试对不兼容的类型进行操作时。了解这个错误的原因以及如何有效解决它&#xff0c;对于提高代码的可靠性和可读性至关重要。本文将详细讨论 TypeError 的成因…...

快速学会C 语言基本概念和语法结构

&#x1f600;前言 本篇博文是关于C 语言的基本概念和语法结构&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力&a…...

Python酷库之旅-第三方库Pandas(172)

目录 一、用法精讲 791、pandas.UInt8Dtype类 791-1、语法 791-2、参数 791-3、功能 791-4、返回值 791-5、说明 791-6、用法 791-6-1、数据准备 791-6-2、代码示例 791-6-3、结果输出 792、pandas.UInt16Dtype类 792-1、语法 792-2、参数 792-3、功能 792-4、…...

Linux系统下minio设置SSL证书进行HTTPS远程连接访问

文章目录 1.配置SSL证书使用HTTPS访问2.MINIO SDK 忽略证书验证3.使用受信任的证书 1.配置SSL证书使用HTTPS访问 生成域名对应的SSL证书&#xff0c;下载Apache版本&#xff0c;我目前只发现Apache这个里面有对应的私钥和证书 私钥重命名为private.key证书重命名为public.crt&…...

npm 包的命名空间介绍,以及@typescript-eslint/typescript-eslint

npm 包的命名空间是一个重要的概念&#xff0c;用于组织和管理相关的包。通过命名空间&#xff0c;开发者可以避免命名冲突、增强包的可读性和可维护性。以下是关于 npm 命名空间的详细介绍&#xff0c;并以 typescript-eslint 作为示例。 1. 命名空间的结构 命名空间的格式为…...

ecovadis评估是什么,有什么提成自己评分等级

EcoVadis评估是一个企业社会责任&#xff08;CSR&#xff09;评级平台&#xff0c;旨在评估全球供应链的可持续性和道德情况。以下是对EcoVadis评估的详细介绍以及提升其评分等级的方法&#xff1a; 一、EcoVadis评估概述 定义&#xff1a;EcoVadis评估通过一系列框架评估公司…...

Vue3中ref、toRef和toRefs之间有什么区别?

前言 Vue 3 引入了组合式 API&#xff0c;其中 ref、toRef 和 toRefs 是处理响应式数据的核心工具。作为高级计算机工程师&#xff0c;我们有必要深入理解这些工具的细微差别&#xff0c;以便在实际项目中更加高效地管理状态。本文将详细解析 ref、toRef 和 toRefs 的区别&…...

react开发技巧

/* eslint-disable no-useless-escape */ const Validator { isEmail: /^([a-zA-Z0-9_\.\-])\(([a-zA-Z0-9\-])\.)([a-zA-Z0-9]{2,4})$/, // 校验邮箱 isPhoneNumber: /^1[3456789]\d{9}$/, // 手机号码验证 isMobileNumber: /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/, //…...

HarmonyOS第一课——HarmonyOS介绍

HarmonyOS第一课 HarmonyOS介绍 HarmonyOS是新一代的智能终端操作系统&#xff08;泛终端服务的载体&#xff09;&#xff1b; 智慧互联协同&#xff0c;全场景交互体验&#xff1b; 核心技术理念&#xff1a; 一次开发 多次部署&#xff1a; 预览 可视化开发UI适配 事件交…...

XCode16中c++头文件找不到解决办法

XCode16中新建Framework&#xff0c;写完自己的c代码后&#xff0c;提示“<string> file not found”等诸如此类找不到c头文件的错误。 工程结构如下&#xff1a; App是测试应用&#xff0c;BoostMath是Framework。基本结构可以参考官方demo&#xff1a;Mix Swift and …...

CSS - 保姆级面试基础扫盲版本一

盒子模型 盒子模型定义&#xff1a; 当对一个盒子模型进行文档布局的时候&#xff0c;浏览器的渲染引擎会根据标准之一的CSS盒子模型&#xff08;CSS basic box model&#xff09;&#xff0c;将所有元素表示成一个个矩阵盒子。 一个盒子通常由四部分组成&#xff1a;border p…...

51c自动驾驶~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/11491137 #BEVWorld BEV潜在空间构建多模态世界模型&#xff0c;全面理解自动驾驶~一、引言 世界模型建模了有关环境的知识&#xff0c;其可以通过给定的条件对未来进行合理的想象。未来想象要求世界模型具有物理规律的理解…...

Redis后台任务有哪些

Redis后台任务 为了有更好的性能表现&#xff0c;redis对于一些比较耗时的操作会异步执行&#xff0c;不阻塞线上请求。文章从源码(redis7.0)来看&#xff0c;aof、rdb文件的关闭&#xff0c;aof文件的刷盘以及部分内存释放会采用异步方式&#xff0c;在后台线程中执行。接下来…...

TPair<TKey, TValue> 键值对

在 Delphi&#xff08;或更准确地说是 Object Pascal&#xff0c;Delphi 的编程语言&#xff09;中&#xff0c;TList<T> 是泛型列表的一个实现&#xff0c;其中 T 是列表中元素的类型。TPair<TKey, TValue> 是一个包含两个元素的记录&#xff08;record&#xff0…...

【杂谈】城市规划教育的危与机

城市规划教育的危与机 &#xff08;赵燕菁 原文为作者在 第21届中国城市规划学科发展论坛上的发言&#xff0c;有删减和改动&#xff09;如有侵权&#xff0c;立即删除 过去几年&#xff0c;尤其是从2022年后房地产市场的下行开始&#xff0c;中国的城市规划陷入前所未有的危…...

金融工程--pine-script 入门

背景 脚本基本组成 指标 常见的趋势类指标&#xff1a;均线类(MAs)、支撑/压力位(Support/Resistance)、趋势线(Trend Lines)、趋势通道(Trend Channels)、一目均衡表(Ichimoku)和 艾略特波浪(ElliotWave)。 均线指标 策略 策略种类 在TradingView上&#xff0c;有许多交易…...

Vue3 跨标签页或跨窗口通信

在 Vue 应用中&#xff0c;跨标签页或跨窗口的通信通常涉及到两个或多个浏览器标签页之间的信息共享。由于每个标签页或窗口都是独立的 JavaScript 执行环境&#xff0c;它们不能直接通过 Vue 或其他 JavaScript 库来直接相互通信。但是&#xff0c;有一些方法可以实现这种跨标…...

Ollama: 使用Langchain的OllamaFunctions

1. 引言 Function call Langchain的Ollama 的实验性包装器OllamaFunctions&#xff0c;提供与 OpenAI Functions 相同的 API。因为网络的原因&#xff0c;OpenAI Functions不一定能访问&#xff0c;但如果能通过Ollama部署的本地模型实现相关的函数调用&#xff0c;还是有很好…...

java质数的判断 C语言指针变量的使用

1. public static void main(String[] args) {Scanner scnew Scanner(System.in);System.out.println("请输入一个值");int num sc.nextInt();boolean flagtrue;for (int i2;i<num;i){if (num%i0){flagfalse;break;}}if (flag){System.out.println(num"是一…...

TensorFlow面试整理-TensorFlow 数据处理

在 TensorFlow 中,数据处理是构建和训练深度学习模型的重要环节。高效地管理、预处理和增强数据可以显著提高模型的训练效率和性能。TensorFlow 提供了强大的 tf.data API 来帮助处理各种数据集。下面是 TensorFlow 数据处理的详细介绍: 1. tf.data.Dataset API tf.data API …...

vue路由的基本使用

vue路由的基本使用 vue-router简介一、路由配置和使用1、安装2、创建路由实例2、在组件中引用路由 router-view ,如APP根组件中直接引用&#xff1a;3、最后还需要把路由挂载到APP实例中&#xff0c;在main.js中注册路由&#xff1a; 二、路由重定向与别名三、声明式导航1、传统…...

数据结构分类

数据结构(data structure)是计算机存储、组织数据的方式&#xff0c;是带有结构特性的数据元素的集合。是相互之间存在一种或多种特定关系的数据元素的集合&#xff0c;即带“结构”的数据元素的集合。这种“结构”指的是数据元素之间存在的关系&#xff0c;分为逻辑结构和存储…...

【STM32】 TCP/IP通信协议--LwIP介绍

LwIP&#xff08;Lightweight IP&#xff09;是一个轻量级的TCP/IP协议栈&#xff0c;专为嵌入式系统设计&#xff0c;以较小的资源消耗实现完整的网络功能。本文将详细介绍LwIP的基本概念、特点、与TCP/IP的区别以及如何在STM32上使用LwIP实现TCP/IP通信。 1. LwIP的定义和设…...

一些面试题整理

第一章、基础 以下是对上述10道面试题的参考答案&#xff1a; 一、Java语言及性能调优 答案&#xff1a; 线程安全问题是指多个线程同时访问共享资源时可能出现的数据不一致或错误的情况。例如&#xff0c;多个线程同时对一个共享变量进行写操作&#xff0c;如果没有适当的同…...

西安市政府网站建设/被代运营骗了去哪投诉

对绝大年夜部分高考生来说&#xff0c;都是以高考成绩能否婚配来抉择黉舍的。这三所黉舍的打算机专业录取分数高低差别&#xff0c;其中北京航空航天大年夜学打算机专业的录取分数最高&#xff0c;其次是哈尔滨产业大年夜学(深圳)&#xff0c;再次是哈尔滨产业大年夜学本部。抉…...

做电商网站企业/app开发公司

PHICOMM(斐讯)N1盒子 - Armbian5.77(Debian 9)刷入EMMC 如需转载请标明出处&#xff1a;http://blog.csdn.net/itas109 技术交流&#xff1a;129518033 文章目录PHICOMM(斐讯)N1盒子 - Armbian5.77(Debian 9)刷入EMMC前言1. 先刷系统到U盘2. 修改uEnv.ini3. 替换dtb文件4. 启动…...

建设网站的公司哪家好/产品推广策划书

转自&#xff1a;http://www.ihacksoft.com/vmware-workstation-12-windows-10.html 直入正题&#xff0c;首先需要准备3个文件。分别是VirtualBox虚拟机安装包、VirtualBox虚拟机增强包以及Ubuntu系统光盘镜像文件。 我们先去virtualbox.的官网&#xff08;https://www. virt…...

万网制作网站吗/品牌seo是什么

略...

狐表做网站/网站推广公司大家好

1 class和struct的区别和联系 在c中&#xff0c;class和struct只有一点不同&#xff0c;它们是可以完全替代使用的。唯一的不同在于&#xff0c;class中的成员默认是private的&#xff0c;而struct中默认是public的。 2 指针和引用的不同 2.1 引用在编译后&#xff0c;本质上还…...

网站建设与运营毕业论文/编程培训机构加盟哪家好

刚开始学scrapy爬虫框架, 一个bug把我心态搞炸了. 找了半天硬是找不出来. 然后重新创了一个项目, 把原代码copy 过来 又可以正常跑了. 懵逼!!! 我也没做什么呀! 对比发现就是多了几行注释. 最后发现 就是注释惹的祸..... 我在 scrapy.cfg 中 写了一行中文注释. 最后删了就好了.…...