【Linux】系统编程线程读写者模式(C++)

目录

一、读写锁

二、读写锁接口

【2.1】设置读写优先

【2.2】初始化

【2.3】销毁

【2.4】加读锁

【2.5】加写锁

【2.6】解锁

三、读写锁实例


一、读写锁

                在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。

 

        这里默认是读锁优先的,因为读者非常的多,但是这样也就会导致写锁的饥饿问题。

        读者写者模型和生产者消费者模型的区别? 读者写者模型和生产者消费者模型最大的区别就是生产者生产数据之后,消费者就会将数据消费掉,其他消费者则无法享受该数据。而读者写者模型中写者进行数据的写入时,所有的读者都可以享受该数据,直到写者再次写入。

读者写者模型中的三重关系?

  • 写者和写者的关系:互斥。

  • 读者和读者的关系:共享。

  • 读者和写者的关系:互斥和同步(当写者进行数据写入时,读者不可以进行数据的读取,当读者进行数据的读取时,写者不可以进行数据的写入,同时读者必须等待写者把数据写完才可以进行数据的写入)。

既然读读不互斥,为何还要加读锁?

  • 如果只是读,是不需要加锁的,加锁本身就有性能上的损耗。

  • 如果读可以不是最新数据,也不需要加锁。

  • 如果读必须是最新数据,必须加读写锁。

  • 读写锁相较于互斥锁的优点仅仅是允许读读的并发,除此之外并无其他。

二、读写锁接口

【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 写者优先,但写者不能递归加锁
*/

【2.2】初始化

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
// 功能: 初始化读写锁
// 参数说明:
// rwlock: 是要进行初始化的读写锁
// attr:是rwlock的属性,此参数一般不关注,可设为NULL

【2.3】销毁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
// 功能: 销毁初始化的锁
// 参数说明:
// rwlock: 是需要进行销毁的锁

【2.4】加读锁

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

【2.5】加写锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

【2.6】解锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

三、读写锁实例

#include <iostream>
#include <pthread.h>
#include <unistd.h>
​
int data = 0; // 全局读写临界资源
pthread_rwlock_t rwlock; // 全局读写锁
​
/* - 读者线程 
*/
void *Reader(void *arg)
{while (true){// 加读锁pthread_rwlock_rdlock(&rwlock);
​std::cout << "reader down:" << data << std::endl;
​// 解锁pthread_rwlock_unlock(&rwlock);sleep(2);}
}
​
/* - 写者线程
*/
void *Writer(void *arg)
{while (true){// 加写锁pthread_rwlock_wrlock(&rwlock);
​std::cout << "writer down:" << ++data << std::endl;
​// 解锁pthread_rwlock_unlock(&rwlock);sleep(1);}
}
​
/* - 程序入口函数 
*/
int main()
{// 初始化读写这锁pthread_rwlock_init(&rwlock, NULL);// 创建读者线程pthread_t r[5];pthread_create(&r[0], nullptr, Reader, nullptr);pthread_create(&r[1], nullptr, Reader, nullptr);pthread_create(&r[2], nullptr, Reader, nullptr);pthread_create(&r[3], nullptr, Reader, nullptr);pthread_create(&r[4], nullptr, Reader, nullptr);
​// 创建读者线程pthread_t w;pthread_create(&w, nullptr, Writer, nullptr);
​// 线程等待for (int i = 0; i < 5; i++){pthread_join(r[i], nullptr);}pthread_join(w, nullptr);
​// 释放读写这锁pthread_rwlock_destroy(&rwlock);return 0;
}
​
// 打印结果:
reader down:0
writer down:1
writer down:2
reader down:2
reader down:2
reader down:2
reader down:2
reader down:2
writer down:3
writer down:4
reader down:4
reader down:4
reader down:4
reader down:4
reader down:4
writer down:5
writer down:6
reader down:6
reader down:6
reader down:6
reader down:6
reader down:6

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/116296.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

14:00面试,14:06就出来了,问的问题过于变态了。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到5月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

使用 docker-compose 构建你的项目

使用 docker-compose 构建你的项目 1. Docker1.1 安装1.2 docker-compose 2 准备项目2.1 初始化一个node项目4. 准备一个 Dockerfile 文件5. 构建镜像 3.docker-compose构建3.1 配置docker-compose.yml 文件3.2 编排多个服务 重新构建镜像 --force-rm 删除构建过程中的临时容器…

AI-Chat,一款集全网ai功能的应用(附下载链接)

AI-Chat是一款综合性的聊天机器人&#xff0c;集成了多种先进的模型和功能。它采用了GPT4.0、联网版GPT和清华模型等多种模型&#xff0c;使得其具备更强大的语言处理能力。同时&#xff0c;AI-Chat还融合了AI绘画模型&#xff0c;例如Stable Diffusion绘画、文生图、图生图、艺…

硬件知识积累 网口接口 百兆,千兆,万兆 接口介绍与定义 (RJ45 --简单介绍)

1. 百兆网口 1.1百兆网的定义 百兆网的意思是是100Mb/S&#xff0c;中文叫做100兆位/秒。 1.2百兆网口的常用连接器 1.1.1 一般百兆网口的连接器一般是RJ45 下面是 实物图&#xff0c; 原理图&#xff0c;封装图。 1.3 百兆网口连接线的介绍 1.3.1 百兆需要使用的线的定义 百…

Flowable主要子流程介绍

1. 内嵌子流程 &#xff08;1&#xff09;说明 内嵌子流程又叫嵌入式子流程&#xff0c;它是一个可以包含其它活动、分支、事件&#xff0c;等的活动。我们通常意义上说的子流程通常就是指的内嵌子流程&#xff0c;它表现为将一个流程&#xff08;子流程&#xff09;定…

十四、流式编程(2)

本章概要 中间操作 跟踪和调试流元素排序移除元素应用函数到元素在 map() 中组合流 中间操作 中间操作用于从一个流中获取对象&#xff0c;并将对象作为另一个流从后端输出&#xff0c;以连接到其他操作。 跟踪和调试 peek() 操作的目的是帮助调试。它允许你无修改地查看…

Learn Prompt- Midjourney 图片生成:基本设置和预设

/settings指令为模型版本、样式值、质量值和升级器版本等常用选项提供切换按钮。 备注 添加到提示末尾的参数将覆盖/settings中的设置。 模型版本​ 1️⃣ MJ Version 12️⃣ MJ Version 23️⃣ MJ Version 34️⃣ MJ Version 45️⃣ MJ Version 5&#x1f308; Niji Mode&a…

数据结构与算法-时间复杂度与空间复杂度

数据结构与算法 &#x1f388;1.概论&#x1f52d;1.1什么是数据结构&#xff1f;&#x1f52d;1.2什么是算法&#xff1f; &#x1f388;2.算法效率&#x1f52d;2.1如何衡量一个算法的好坏&#xff1f;&#x1f52d;2.2算法的复杂度&#x1f52d;2.3时间复杂度&#x1f4d6;2…

Swift SwiftUI 隐藏键盘

如果仅支持 iOS 15 及更高版本&#xff0c;则可以通过聚焦和取消聚焦来激活和关闭文本字段的键盘。 在最简单的形式中&#xff0c;这是使用 FocusState 属性包装器和 focusable() 修饰符完成的-第一个存储一个布尔值&#xff0c;用于跟踪第二个当前是否被聚焦。 Code struct C…

分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测

分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测 目录 分类预测 | MATLAB实现WOA-CNN-GRU-Attention数据分类预测分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现WOA-CNN-GRU-Attention数据分类预测&#xff0c;运行环境Matlab2021b及以上&…

使用python处理MNIST数据集

文章目录 一. MNIST数据集1.1 什么是MNIST数据集1.2MNIST数据集文件格式1.3使用python访问MNIST数据集文件内容 附录程序源码 一. MNIST数据集 1.1 什么是MNIST数据集 MNIST数据集是入门机器学习/识别模式的最经典数据集之一。最早于1998年Yan Lecun在论文:[Gradient-based l…

yolo增加slide loss,改善样本不平衡问题

slide loss的主要作用是让模型更加关注难例&#xff0c;可以轻微的改善模型在难例检测上的效果 论文地址&#xff1a;https://arxiv.org/pdf/2208.02019.pdf 代码&#xff1a;GitHub - Krasjet-Yu/YOLO-FaceV2: YOLO-FaceV2: A Scale and Occlusion Aware Face Detector 样本不…