0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux下线程间通讯---读写锁和条件变量

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-08-26 20:44 次阅读

Linux下线程间通讯---读写锁和条件变量

1.读写锁简介

读写锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。

一次只有一个线程可以占有写模式的读写锁,但是可以有多个线程同时占有读模式的读写锁。正是因为这个特性,当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。

当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进行加锁,它必须直到所有的线程释放锁。

通常,当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求长期阻塞。

读写锁适合于对数据结构的读次数比写次数多得多的情况。因为,读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁又叫共享-独占锁。

pYYBAGMIwECAM9HdAACMyXIU438691.png#pic_center

1.1 相关函数

#include 
//销毁读写锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
//读写锁初始化
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
//读加锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
//写加锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
//解锁
pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

1.2 示例

  创建两个线程,2个子线程读数据,主线程负责写数据。

#include 
#include 
#include 
int data=0;
pthread_rwlock_t rwlock;
/*读线程1*/
void *pth1_work(void *arg)
{
	int a;
	while(1)
	{
		pthread_rwlock_rdlock(&rwlock);//读上锁
		a=data;
		printf("----------------线程1读数据-----------------------\n");
		sleep(5);
		printf("[%s]线程1,data=%d\n",__FUNCTION__,a);
		pthread_rwlock_unlock(&rwlock);//解锁
		usleep(10);
	}
}
/*读线程2*/
void *pth2_work(void *arg)
{
	int a;
	while(1)
	{
		pthread_rwlock_rdlock(&rwlock);//读上锁
		a=data;
		printf("----------------线程2读数据-----------------------\n");
		sleep(5);
		printf("[%s]线程1,data=%d\n",__FUNCTION__,a);
		pthread_rwlock_unlock(&rwlock);//解锁
		usleep(10);
	}
}
int main()
{
	
	pthread_rwlock_init(&rwlock,NULL);/*创建读写锁*/
	/*创建线程1*/
	pthread_t id;
	pthread_create(&id,NULL,pth1_work,NULL);
	pthread_detach(id);//设置为分离属性	
	
	/*创建线程2*/
	pthread_create(&id,NULL,pth2_work,NULL);
	pthread_detach(id);//设置为分离属性
	/*写线程*/
	while(1)
	{
		pthread_rwlock_wrlock(&rwlock);//写加锁
		printf("主线程写数据............\n");
		sleep(3);
		data+=100;
		printf("主线程写数据完\n");
		pthread_rwlock_unlock(&rwlock);//解锁
		usleep(10);
	}
}
poYBAGMIwECAd_rXAAH4w3uS_fg183.png#pic_center

2.条件变量

2.1 条件变量简介

条件变量是线程可用的一种同步机制,条件变量给多个线程提供了一个回合的场所,条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生。

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

注意:条件变量需要和互斥锁一起使用。

例如:线程4推送屏幕图像数据给各个子线程,需要1s推送一次;线程1、2、3获取推送的数据的频率则远小于1s时间,若此类情况使用读写锁则会导致子线程频繁获取相同数据帧,极大浪费CPU资源。而使用条件变量则可以有效解决资源浪费问题。

pYYBAGMIwEGATGHHAAFCWYjyWwk022.png#pic_center

2.2 相关函数

#include 
//销毁条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
//动态初始化条件变量
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
//静态初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//等待条件变量产生
pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
//广播唤醒所有线程
int pthread_cond_broadcast(pthread_cond_t *cond);
//随机唤醒一个线程
int pthread_cond_signal(pthread_cond_t *cond);

2.3 示例

  创建5个子线程,子线程等待条件变量产生,主线程捕获 SIGINT(CTRL+C信号)和SIGQUIT(CTRL+\)信号,通过信号实现广播唤醒所有线程和随机唤醒一个线程。

#include 
#include 
#include 
#include 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
pthread_cond_t cond;
void *pth_work(void *arg)
{
	int cnt=(int *)arg;	
	pthread_mutex_lock(&mutex);//互斥锁上锁
	printf("线程%d运行中.....\n",cnt);
	pthread_cond_wait(&cond,&mutex);//等待条变量产生,本身自带解锁功能

	printf("线程%d唤醒成功,id=%lu\n",cnt,pthread_self());
	pthread_mutex_unlock(&mutex);//互斥锁解锁
}
void sig_work(int sig)
{
	if(sig==SIGINT)
	{
		pthread_mutex_lock(&mutex);//互斥锁上锁
		pthread_cond_signal (&cond);//随机唤醒一个线程
		pthread_mutex_unlock(&mutex);//互斥锁解锁
	}
	if(sig==SIGQUIT)
	{
		pthread_mutex_lock(&mutex);//互斥锁上锁
		pthread_cond_broadcast(&cond);//广播唤醒所有线程
		pthread_mutex_unlock(&mutex);//互斥锁解锁
	}
}
int main()
{
	signal(SIGINT,sig_work);//捕获CTRL+C
	signal(SIGQUIT,sig_work);//捕获CTRL+\
	/*创建条件变量*/
	pthread_cond_init(&cond,NULL);
	pthread_t pth[5];
	int i=0;
	for(i=0;i<5;i++)
	{
		pthread_create(&pth[i],NULL,pth_work,(void*)i);
	}
	for(i=0;i<5;i++)
	{
		pthread_join(pth[i],NULL);
	}
	pthread_cond_destroy(&cond);
	pthread_mutex_destroy(&mutex);
	printf("所有线程结束\n");
	return 0;
}   
poYBAGMIwEGAGDFpAAGlFBJ7RUY395.png#pic_center

2.4 示例2

编写程序完成如下功能:
 1)有一int型全局变量g_Flag初始值为0;
 2) 在主线称中起动线程1,打印“this is thread1”,并将g_Flag设置为1
 3) 在主线称中启动线程2,打印“this is thread2”,并将g_Flag设置为2
 4) 主线程在检测到g_Flag从1变为2,或者从2变为1的时候退出

#include 
#include 
#include 
#include 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int g_Flag=0;
void *pth_work(void *arg)
{
	printf("this is thread1\n");
	pthread_mutex_lock(&mutex);
	if(g_Flag==2)
	{
		g_Flag=1;
		pthread_cond_signal(&cond);//随机唤醒一个线程
	}
	else 
	{
		g_Flag=1;
	}
	printf("线程1:%d\n",g_Flag);
	pthread_mutex_unlock(&mutex);
}

void *pth2_work(void *arg)
{
	printf("this is thread2\n");
	pthread_mutex_lock(&mutex);
	if(g_Flag==1)
	{
		g_Flag=2;;
		pthread_cond_signal(&cond);//随机唤醒一个线程
	}
	else 
	{
		g_Flag=2;
	}
	printf("线程2:%d\n",g_Flag);
	pthread_mutex_unlock(&mutex);
}
int main()
{
	pthread_t pth;
	/*创建线程1*/
	pthread_create(&pth,NULL,pth_work,NULL);
	pthread_detach(pth);//设置为分离属性
	/*创建线程2*/
	pthread_create(&pth,NULL,pth2_work,NULL);
	pthread_detach(pth);//设置为分离属性
	
	pthread_mutex_lock(&mutex);
	pthread_cond_wait(&cond,&mutex);
	pthread_mutex_unlock(&mutex);

	pthread_cond_destroy(&cond);
	pthread_mutex_destroy(&mutex);
	printf("所有线程结束\n");
	return 0;
}  

运行效果:

pYYBAGMIwEGAd5IbAADSZXzCm5M271.png#pic_center

审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11225

    浏览量

    208910
  • 线程
    +关注

    关注

    0

    文章

    504

    浏览量

    19648
收藏 人收藏

    评论

    相关推荐

    Linux下线程编程

    Linux下线程编程
    的头像 发表于 08-24 15:42 1880次阅读

    Linux系统中线程同步方式中的条件变量方法

    今天主要和大家聊一聊,如何使用Linux线程同步方式中的条件变量
    发表于 11-08 09:16 511次阅读

    线程编程之三 线程通讯

    线程编程之三 线程通讯七、线程通讯  一般而言
    发表于 10-22 11:43

    Linux线程线程同步

    pthread_mutex_lock先加锁,操作完之后pthread_mutex_unlock再解锁。5、线程同步条件变量:使用条件
    发表于 12-08 14:14

    Linux C 多线程编程之互斥条件变量实例详解

    Test()二、条件变量这里主要说说 pthread_cond_wait()的用法,在下面有说明。条件变量是利用线程
    发表于 06-03 17:13

    浅析linux下的条件变量

      一.条件变量     条件变量是用来等待线程而不是上锁的,条件
    发表于 07-12 08:10

    Linux线程同步方法

    Linux下提供了多种方式来处理线程同步,最常用的是互斥条件变量和信号量。
    发表于 07-19 07:24

    很多变量线程读写是使用关中断好还是使用互斥进行保护呢?

    我想问一下,就是我有很多变量会多线程读写操作,有一些会比较频繁,我读写的时候是使用中断去保护还是增加互斥量去保护。 1.如果加互斥量,当前低优先级
    发表于 05-05 14:14

    了解Linux线程线程同步

    进程通信IPC,线程可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
    发表于 04-23 14:23 712次阅读
    了解<b class='flag-5'>Linux</b>多<b class='flag-5'>线程</b>及<b class='flag-5'>线程</b><b class='flag-5'>间</b>同步

    详谈Linux操作系统的三种状态的读写

    读写是另一种实现线程同步的方式。与互斥量类似,但读写将操作分为读、写两种方式,可以多个
    的头像 发表于 09-27 14:57 3085次阅读

    详谈Linux操作系统编程的条件变量

    条件变量是用来等待线程而不是上锁的,条件变量通常和互斥一起使用。
    的头像 发表于 09-27 15:23 1970次阅读
    详谈<b class='flag-5'>Linux</b>操作系统编程的<b class='flag-5'>条件</b><b class='flag-5'>变量</b>

    Linux下线程通讯--互斥

    互斥是一种简单的加锁的方法来控制对共享资源的存取,当多个线程访问公共资源时,为了保证同一时刻只有一个线程独占资源,就可以通过互斥加以限制,在一个时刻只能有一个
    的头像 发表于 08-24 15:53 1935次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>下线程</b><b class='flag-5'>间</b><b class='flag-5'>通讯</b>--互斥<b class='flag-5'>锁</b>

    Linux线程条件变量是什么意思

    条件变量 条件变量用于自动阻塞线程,直到某个特定事件发生或某个条件满足为止,通常情况下,
    的头像 发表于 07-21 11:18 490次阅读

    读写的实现原理规则

    读写 互斥或自旋要么是加锁状态、要么是不加锁状态,而且一次只有一个线程可以对其加锁。 读写
    的头像 发表于 07-21 11:21 865次阅读
    <b class='flag-5'>读写</b><b class='flag-5'>锁</b>的实现原理规则

    互斥条件变量的使用

    本文主要分为三个部分: 第一部分简要介绍线程的概念及其使用 第二部分主要介绍互斥条件变量的使用(重点探讨pthread_cond_wait) 第三部分参考运行IBM的多
    的头像 发表于 11-10 14:51 578次阅读
    互斥<b class='flag-5'>锁</b>及<b class='flag-5'>条件</b><b class='flag-5'>变量</b>的使用