首页 > 编程语言 >系统编程-读写锁

系统编程-读写锁

时间:2023-09-01 21:38:22浏览次数:33  
标签:rwlock 变量 读写 编程 系统 cond pthread mutex

读写锁

  1. 互斥锁的缺陷

    • 互斥锁无论读取共享资源,还是修改共享资源,都是要上锁,而且在上锁期间,其它线程不能上锁
  2. 概念

    • 与互斥锁类似,但是读写锁允许更高的并行性。特性是,写独占,读共享
  3. 读写锁的状态

    • 特别强调:读写锁只有一把,但具有两种状态
    • 读模式下的加锁状态(读锁)
    • 写模式下的加锁状态(写锁)
  4. 读写锁的特性

    • 读写锁是“写锁”时,解锁前,所有对该锁该锁的线程都阻塞
    • 读写锁是“读锁”时,如果线程以读模式对其加锁会成功;写模式加锁就会阻塞
    • 读写锁也叫共享-独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,是以独占模式锁住的
    • 写独占,读共享
    • 读写锁非常适合对于数据结构读的次数远大于写的情况
    • 写锁优先级高
  5. 读写锁函数的接口

    • 定义一个读写锁变量----->pthread_rwlock_t rwlock

    • 初始化读写锁变量----->pthread_rwlock_init()

    #include <pthread.h>
    	int pthread_rwlock_init(
    		pthread_rwlock_t *restrict rwlock,  //参数1:读写锁变量的地址
    		const pthread_rwlockattr_t *restrict attr  //参数2:属性,一般是NULL
    	);
    	// 返回值:成功0,失败非0错误码
    
    • 读锁上锁----->pthread_rwlock_rdlock()
    #include <pthread.h>
    	int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);  // 参数:读写锁变量的地址
    	// 返回值:成功0,失败非0错误码
    
    • 写锁上锁----->pthread_rwlock_wrlock()
    #include <pthread.h>
    	int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);  // 参数:读写锁变量的地址
    	// 返回值:成功0,失败非0错误码
    
    • 读写锁解锁---->pthread_rwlock_unlock
    #include <pthread.h>
    	int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);  // 参数:读写锁变量的地址
    	// 返回值:成功0,失败非0错误码
    
    • 销毁读写锁---->pthread_rwlock_destroy
    #include <pthread.h>
    	int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);  // 参数:读写锁变量的地址
    	// 返回值:成功0,失败非0错误码
    
    • 案例:
    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    
    // 读写锁变量
    pthread_rwlock_t rwlock;
    
    // 全局变量
    int main_val = 0;
    
    void *routine1(void *arg)
    {
    	//写锁
    	pthread_rwlock_wrlock(&rwlock);
    	//写操作
    	main_val=100;
    	for(int i=0;i<5;i++)
    	{
    		sleep(1);
    		main_val+=main_val*i;
    		printf("%d routine1 100 main_val:%d\n",i,main_val);
    	}
    	//解锁
    	 pthread_rwlock_unlock(&rwlock);
    	//退出
    	pthread_exit(NULL);
    }
    void *routine2(void *arg)
    {
    	//写锁
    	pthread_rwlock_wrlock(&rwlock);
    	//写操作
    	main_val=200;
    	for(int i=0;i<5;i++)
    	{
    		sleep(1);
    		main_val+=main_val*i;
    		printf("%d routine2 200 main_val:%d\n",i,main_val);
    	}
    	//解锁
    	pthread_rwlock_unlock(&rwlock);
    	//退出
    	pthread_exit(NULL);
    }
    void *routine3(void *arg)
    {
    	sleep(1);
    	//读锁
    	pthread_rwlock_rdlock(&rwlock);
    	//读操作
    	for(int i=0;i<5;i++)
    	{
    		sleep(1);
    		printf("routine3 main_val:%d\n",main_val);
    	}
    	//解锁
    	pthread_rwlock_unlock(&rwlock);
    	//退出
    	pthread_exit(NULL);
    }
    void *routine4(void *arg)
    {
    	sleep(1);
    	//读锁
    	pthread_rwlock_rdlock(&rwlock);
    	//读操作
    	for(int i=0;i<5;i++)
    	{
    		sleep(1);
    
    		printf("routine4  main_val:%d\n",main_val);
    	}
    	//解锁
    	pthread_rwlock_unlock(&rwlock);
    	//退出
    	pthread_exit(NULL);
    }
    
    int main(int argc, char const *argv[])
    {
    	// 初始化读写锁
    	pthread_rwlock_init(&rwlock, NULL);
    
    	// 线程ID数组
    	pthread_t tid[4];
    
    	// 线程函数指针数组
    	void* (*fp[4])(void*) = {routine1, routine2, routine3, routine4};
    
    	// 创建线程
    	for (int i = 0; i < 4; ++i)
    	{
    		pthread_create(&tid[i], NULL, fp[i], NULL);
    	}
    
    	// 等待线程结束回收
    	for (int i = 0; i < 4; ++i)
    	{
    		pthread_join(tid[i], NULL);
    	}
    
    	// 销毁读写锁
    	pthread_rwlock_destroy(&rwlock);
    
    	return 0;
    }
    

条件变量

  1. 什么是条件变量

    • 线程因为某一条件/情况不成立,进入一个变量中等待,这个存放线程的变量的就是条件变量。条件变量本身不是锁,但它可以造成线程堵塞。通常是与互斥锁配合使用。给多线程提供一个会和的场合
  2. 关于条件变量的函数接口

    • 定义一个条件变量----->pthread_cond_t cond

    • 初始化条件变量----->pthread_cond_init()

    #include <pthread.h>
    	int pthread_cond_init(
    		pthread_cond_t *cond,  // 参数1:条件变量地址
    		pthread_condattr_t *cond_attr  // 参数2:普通属性,NULL
    	);
    	// 返回值:成功0,失败非0错误码
    
    • 如何进入条件变量等待
    #include <pthread.h>
    	int pthread_cond_wait(
    		pthread_cond_t *cond,
    		pthread_mutex_t *mutex
    	);
    	int pthread_cond_timedwait(
    		pthread_cond_t *cond,  // 参数1:条件变量的地址
    		pthread_mutex_t *mutex,  // 参数2:互斥锁的地址---->进入条件变量会自动解锁
    		const struct timespec *abstime  // 参数3: 绝对时间
    	);
    	// 返回值:成功0,失败非0错误码
    
    • 关于pthread_cond_timedwait
    struct timespec
    {
    	time_t tv_sec;  // 秒
    	long tv_nsec;  // 纳秒
    }
    

    获取当前时间:

    	time_t cur=time(NULL);
    	struct timespec t;
    	t.tvsec=cur+1;
    	pthread_cond_timedwait(&cond, &mutex, &t);
    
    • 如何唤醒条件变量中等待的线程?---->线程离开条件变量会自动上锁
    #include <pthread.h>
    	// 单播:随机唤醒(至少)一个在条件变量的线程
    	int pthread_cond_signal(pthread_cond_t *cond);  // 参数: 条件变量的地址
    	// 唤醒所有在条件变量中等待的线程
    	int pthread_cond_broadcast(pthread_cond_t *cond);  // 参数: 条件变量的地址
    	// 返回值:成功0,失败非0错误码
    
    • 销毁条件变量------>pthread_cond_destroy()
    #include <pthread.h>
    	int pthread_cond_destroy(pthread_cond_t *cond);  // 参数:条件变量的地址
    	// 返回值:成功0,失败非0错误码
    

    -案例:
    练习:有4个小孩,每个小孩的任务就是领取生活费1000,他们回学校之前银行卡父亲先打个两千,2个小孩可以领取到,就是两个线程退出,另外两个进入条件变量等待,父亲再打钱1000,唤醒所有的小孩来拿钱,过了一会,再打1000,再唤醒最后一个小孩起来拿钱赶紧去上学。

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    
    
    // 互斥锁变量
    pthread_mutex_t mutex;
    // 条件变量
    pthread_cond_t cond;
    
    int money = 2000;
    
    void* func1(void*arg)
    {
    	pthread_mutex_lock(&mutex);
    	if(money < 1000)
    	{
    		pthread_cond_wait(&cond, &mutex);
    	}
    	money -= 1000;
    	printf("boy1 拿到钱了\n");
    
    	pthread_mutex_unlock(&mutex);
    	pthread_exit(NULL);
    }
    
    void* func2(void*arg)
    {
    	pthread_mutex_lock(&mutex);
    	if(money < 1000)
    	{
    		pthread_cond_wait(&cond, &mutex);
    	}
    	money -= 1000;
    	printf("boy2 拿到钱了\n");
    
    	pthread_mutex_unlock(&mutex);
    	pthread_exit(NULL);
    }
    
    void* func3(void*arg)
    {
    	pthread_mutex_lock(&mutex);
    	if(money < 1000)
    	{
    		pthread_cond_wait(&cond, &mutex);
    	}
    	money -= 1000;
    	printf("boy3 拿到钱了\n");
    
    	pthread_mutex_unlock(&mutex);
    	pthread_exit(NULL);
    }
    
    void* func4(void*arg)
    {
    	pthread_mutex_lock(&mutex);
    	if(money < 1000)
    	{
    		pthread_cond_wait(&cond, &mutex);
    	}
    	money -= 1000;
    	printf("boy4 拿到钱了\n");
    
    	pthread_mutex_unlock(&mutex);
    	pthread_exit(NULL);
    }
    
    int main(int argc, char const *argv[])
    {
    	// 初始化互斥锁
    	pthread_mutex_init(&mutex, NULL);
    	// 初始化条件变量
    	pthread_cond_init(&cond, NULL);
    
    	pthread_t tid[4];
    
    	void* (*fp[4])(void*) = {func1, func2, func3, func4};
    	for (int i = 0; i < 4; ++i)
    	{
    		pthread_create(&tid[i], NULL, fp[i], NULL);
    	}
    
    	for (int i = 0; i < 5; ++i)
    	{
    		printf("当前延时%d秒\n", i);
    		sleep(1);
    	}
    	printf("father准备打钱了\n");
    	pthread_mutex_lock(&mutex);
    	money += 1000;
    	pthread_mutex_unlock(&mutex);
    	pthread_cond_broadcast(&cond);
    
    	for (int i = 0; i < 5; ++i)
    	{
    		printf("当前延时%d秒\n", i);
    		sleep(1);
    	}
    	printf("father准备打钱了\n");
    	pthread_mutex_lock(&mutex);
    	money += 1000;
    	pthread_mutex_unlock(&mutex);
    	pthread_cond_broadcast(&cond);
    
    	for (int i = 0; i < 4; ++i)
    	{
    		pthread_join(tid[i],NULL);
    	}
    
    	pthread_mutex_destroy(&mutex);
    	pthread_cond_destroy(&cond);
    
    	return 0;
    }
    

    终端显示:
    image

条件变量生产者消费者模型

  1. 概念
    • 线程同步典型的案例即为生产者消费模型,而借助条件变量来实现这一模型,是比较常见的一种方法。假定有两个线程,一个线程模拟生产者行为,一个去模拟消费者行为。两个线程同时操作一个共享资源(一般称之为汇聚),生产向其中添加商品,消费就是消费者去消耗掉商品

标签:rwlock,变量,读写,编程,系统,cond,pthread,mutex
From: https://www.cnblogs.com/bcc0729/p/17672001.html

相关文章

  • C++一阶--通讯录管理系统
    照着黑马程序员C++视频敲的,可以快速回忆起当时上课学的东西。其实当时期末的那个设计我也是敲得这个”通讯录管理系统“,这算是我大学以及编程的第一个成就。再次完成亦有感慨。先说我我想说的:体会了结构体增删改查的实现冒泡排序指针中”&“与”*“的区别函数封装的妙处......
  • COMP SCI 3004操作系统的虚拟内存模拟
    SCI3004COMPSCI3004/7064OperatingSystemsPractical2–VirtualMemorySimulationAimBydoingthispracticalwork,youwilllearnhowtoimplementpagereplacementalgorithms,gainexperienceincreatingandevaluatingasimplesimulator,anddevelopyour......
  • COMP3610编程技巧几点看法
    COMP3610/6361PrinciplesofProgrammingLanguagesAssignment1ver1.1SubmissionGuidelinesDuetime:Aug31,2023,11am(CanberraTime)SubmitapdfviaWattle.Scansofhand-writtentextarefine,aslongastheyarereadableandneat.Pleasereadandsign......
  • AI辅助编程测试2023.9.1
    今天考虑做一个需求WinForm程序中,将DevExpress中的SpreadsheetControl控件的[Ctrl+S]快捷键禁掉,避免用户自行将程序中提供的表格进行另存。我将下面这句话拿给各个AI工具,以及搜索工具关键词:DevExpress的SpreadsheetControl控件,如何能禁用ctrl+S这个快捷键  POE中的chatGPT3......
  • 编程中的参数
    一、参数的概念与作用参数是编程中的重要概念之一,用于向函数或方法传递输入值。在编程中,我们经常需要对不同的数据进行处理,而参数的引入使得函数能够根据不同的输入值产生不同的输出结果。参数可以帮助我们定义函数的行为,并且使得函数更加可复用和灵活。参数的作用主要有两个方......
  • 如何学习编程
    如何学习编程编程是当今世界最热门技能之一,而且它的重要性在不断增加。然而,对于初学者来说,编程策划可能看起来像是一片未知的领域。幸运的是,学习编程并不是一项艰难的任务。通过采取一些有效的学习方法和策略,任何人都可以掌握编程技能。在本文中,我们将介绍一些学习编程的建议和技......
  • 银河麒麟服务器操作系统V10SP2离线安装Google Chrome浏览器
    https://blog.csdn.net/ShenSeKyun/article/details/132224932https://www.google.cn/chrome/index.htmlGOOGLE网址最下方下载LINUX版本的浏览器安装包打开终端,输入rpm-ivhgoogle-chrome-stable_current_x86_64.rpmyuminstall google-chrome-stable_current_x86_64.rpm......
  • Android并发编程高级面试题汇总(含详细解析 十五)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......
  • 推荐查看Android系统源码的网址
    地址1:http://androidxref.comAndroid源码从1.6到9.0源码比较老,但是查询搜索功能还是很齐全的有想要了解老版本的源码不错的选择地址2:http://aospxref.comAndroid源码从5.0到13.0源码很新但是过早的源码没有可以结合其他的网站使用,网站页面布局不是很好看,浏览器没有完全适配部分源......
  • MDC设备数据采集分析系统方案
    生产计划:◆现时生产中正在进行的是哪些工作或生产哪些部件?◆工序、零件、工单等加工任务信息在设备上的用时情况不明?◆谁在进行零部件的生产?哪一班?◆零部件的生产时间如何?◆零部件当前正在哪一台机器上制造?◆生产停止的原因是什么?◆产量是由于哪些原因下降?◆停工时间的成本......