RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux下線程間通訊---讀寫(xiě)鎖和條件變量

嵌入式技術(shù) ? 來(lái)源:嵌入式技術(shù) ? 作者:嵌入式技術(shù) ? 2022-08-26 20:44 ? 次閱讀

Linux下線程間通訊---讀寫(xiě)鎖和條件變量

1.讀寫(xiě)鎖簡(jiǎn)介

讀寫(xiě)鎖,它把對(duì)共享資源的訪問(wèn)者劃分成讀者和寫(xiě)者,讀者只對(duì)共享資源進(jìn)行讀訪問(wèn),寫(xiě)者則需要對(duì)共享資源進(jìn)行寫(xiě)操作。

一次只有一個(gè)線程可以占有寫(xiě)模式的讀寫(xiě)鎖,但是可以有多個(gè)線程同時(shí)占有讀模式的讀寫(xiě)鎖。正是因?yàn)檫@個(gè)特性,當(dāng)讀寫(xiě)鎖是寫(xiě)加鎖狀態(tài)時(shí),在這個(gè)鎖被解鎖之前,所有試圖對(duì)這個(gè)鎖加鎖的線程都會(huì)被阻塞。

當(dāng)讀寫(xiě)鎖在讀加鎖狀態(tài)時(shí),所有試圖以讀模式對(duì)它進(jìn)行加鎖的線程都可以得到訪問(wèn)權(quán), 但是如果線程希望以寫(xiě)模式對(duì)此鎖進(jìn)行加鎖,它必須直到所有的線程釋放鎖。

通常,當(dāng)讀寫(xiě)鎖處于讀模式鎖住狀態(tài)時(shí),如果有另外線程試圖以寫(xiě)模式加鎖,讀寫(xiě)鎖通常會(huì)阻塞隨后的讀模式鎖請(qǐng)求,這樣可以避免讀模式鎖長(zhǎng)期占用,而等待的寫(xiě)模式鎖請(qǐng)求長(zhǎng)期阻塞。

讀寫(xiě)鎖適合于對(duì)數(shù)據(jù)結(jié)構(gòu)的讀次數(shù)比寫(xiě)次數(shù)多得多的情況。因?yàn)?,讀模式鎖定時(shí)可以共享, 以寫(xiě)模式鎖住時(shí)意味著獨(dú)占, 所以讀寫(xiě)鎖又叫共享-獨(dú)占鎖。

pYYBAGMIwECAM9HdAACMyXIU438691.png#pic_center

1.1 相關(guān)函數(shù)

#include 
//銷(xiāo)毀讀寫(xiě)鎖
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
//讀寫(xiě)鎖初始化
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);
//寫(xiě)加鎖
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 示例

??創(chuàng)建兩個(gè)線程,2個(gè)子線程讀數(shù)據(jù),主線程負(fù)責(zé)寫(xiě)數(shù)據(jù)。

#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讀數(shù)據(jù)-----------------------\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讀數(shù)據(jù)-----------------------\n");
		sleep(5);
		printf("[%s]線程1,data=%d\n",__FUNCTION__,a);
		pthread_rwlock_unlock(&rwlock);//解鎖
		usleep(10);
	}
}
int main()
{
	
	pthread_rwlock_init(&rwlock,NULL);/*創(chuàng)建讀寫(xiě)鎖*/
	/*創(chuàng)建線程1*/
	pthread_t id;
	pthread_create(&id,NULL,pth1_work,NULL);
	pthread_detach(id);//設(shè)置為分離屬性	
	
	/*創(chuàng)建線程2*/
	pthread_create(&id,NULL,pth2_work,NULL);
	pthread_detach(id);//設(shè)置為分離屬性
	/*寫(xiě)線程*/
	while(1)
	{
		pthread_rwlock_wrlock(&rwlock);//寫(xiě)加鎖
		printf("主線程寫(xiě)數(shù)據(jù)............\n");
		sleep(3);
		data+=100;
		printf("主線程寫(xiě)數(shù)據(jù)完\n");
		pthread_rwlock_unlock(&rwlock);//解鎖
		usleep(10);
	}
}
poYBAGMIwECAd_rXAAH4w3uS_fg183.png#pic_center

2.條件變量

2.1 條件變量簡(jiǎn)介

條件變量是線程可用的一種同步機(jī)制,條件變量給多個(gè)線程提供了一個(gè)回合的場(chǎng)所,條件變量和互斥量一起使用,允許線程以無(wú)競(jìng)爭(zhēng)的方式等待特定的條件發(fā)生。

條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括兩個(gè)動(dòng)作:一個(gè)線程等待"條件變量的條件成立"而掛起;另一個(gè)線程使"條件成立"(給出條件成立信號(hào))。為了防止競(jìng)爭(zhēng),條件變量的使用總是和一個(gè)互斥鎖結(jié)合在一起。

注意:條件變量需要和互斥鎖一起使用。

例如:線程4推送屏幕圖像數(shù)據(jù)給各個(gè)子線程,需要1s推送一次;線程1、2、3獲取推送的數(shù)據(jù)的頻率則遠(yuǎn)小于1s時(shí)間,若此類(lèi)情況使用讀寫(xiě)鎖則會(huì)導(dǎo)致子線程頻繁獲取相同數(shù)據(jù)幀,極大浪費(fèi)CPU資源。而使用條件變量則可以有效解決資源浪費(fèi)問(wèn)題。

pYYBAGMIwEGATGHHAAFCWYjyWwk022.png#pic_center

2.2 相關(guān)函數(shù)

#include 
//銷(xiāo)毀條件變量
int pthread_cond_destroy(pthread_cond_t *cond);
//動(dòng)態(tài)初始化條件變量
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
//靜態(tài)初始化條件變量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//等待條件變量產(chǎn)生
pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
//廣播喚醒所有線程
int pthread_cond_broadcast(pthread_cond_t *cond);
//隨機(jī)喚醒一個(gè)線程
int pthread_cond_signal(pthread_cond_t *cond);

2.3 示例

??創(chuàng)建5個(gè)子線程,子線程等待條件變量產(chǎn)生,主線程捕獲 SIGINT(CTRL+C信號(hào))和SIGQUIT(CTRL+\)信號(hào),通過(guò)信號(hào)實(shí)現(xiàn)廣播喚醒所有線程和隨機(jī)喚醒一個(gè)線程。

#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運(yùn)行中.....\n",cnt);
	pthread_cond_wait(&cond,&mutex);//等待條變量產(chǎn)生,本身自帶解鎖功能

	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);//隨機(jī)喚醒一個(gè)線程
		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+\
	/*創(chuàng)建條件變量*/
	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("所有線程結(jié)束\n");
	return 0;
}   
poYBAGMIwEGAGDFpAAGlFBJ7RUY395.png#pic_center

2.4 示例2

編寫(xiě)程序完成如下功能:
?1)有一int型全局變量g_Flag初始值為0;
?2) 在主線稱中起動(dòng)線程1,打印“this is thread1”,并將g_Flag設(shè)置為1
?3) 在主線稱中啟動(dòng)線程2,打印“this is thread2”,并將g_Flag設(shè)置為2
?4) 主線程在檢測(cè)到g_Flag從1變?yōu)?,或者從2變?yōu)?的時(shí)候退出

#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);//隨機(jī)喚醒一個(gè)線程
	}
	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);//隨機(jī)喚醒一個(gè)線程
	}
	else 
	{
		g_Flag=2;
	}
	printf("線程2:%d\n",g_Flag);
	pthread_mutex_unlock(&mutex);
}
int main()
{
	pthread_t pth;
	/*創(chuàng)建線程1*/
	pthread_create(&pth,NULL,pth_work,NULL);
	pthread_detach(pth);//設(shè)置為分離屬性
	/*創(chuàng)建線程2*/
	pthread_create(&pth,NULL,pth2_work,NULL);
	pthread_detach(pth);//設(shè)置為分離屬性
	
	pthread_mutex_lock(&mutex);
	pthread_cond_wait(&cond,&mutex);
	pthread_mutex_unlock(&mutex);

	pthread_cond_destroy(&cond);
	pthread_mutex_destroy(&mutex);
	printf("所有線程結(jié)束\n");
	return 0;
}  

運(yùn)行效果:

pYYBAGMIwEGAd5IbAADSZXzCm5M271.png#pic_center

審核編輯 黃昊宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11292

    瀏覽量

    209318
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    504

    瀏覽量

    19675
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux下線程編程

    Linux下線程編程
    的頭像 發(fā)表于 08-24 15:42 ?1897次閱讀

    Linux系統(tǒng)中線程同步方式中的條件變量方法

    今天主要和大家聊一聊,如何使用Linux線程同步方式中的條件變量。
    發(fā)表于 11-08 09:16 ?528次閱讀

    線程編程之三 線程通訊

    線程編程之三 線程通訊七、線程通訊  一般而言
    發(fā)表于 10-22 11:43

    Linux線程線程同步

    pthread_mutex_lock先加鎖,操作完之后pthread_mutex_unlock再解鎖。5、線程同步條件變量:使用條件
    發(fā)表于 12-08 14:14

    Linux C 多線程編程之互斥條件變量實(shí)例詳解

    Test()二、條件變量這里主要說(shuō)說(shuō) pthread_cond_wait()的用法,在下面有說(shuō)明。條件變量是利用線程
    發(fā)表于 06-03 17:13

    淺析linux下的條件變量

    ? 一.條件變量 ? ? 條件變量是用來(lái)等待線程而不是上鎖的,條件
    發(fā)表于 07-12 08:10

    Linux線程同步方法

    Linux下提供了多種方式來(lái)處理線程同步,最常用的是互斥、條件變量和信號(hào)量。
    發(fā)表于 07-19 07:24

    很多變量線程讀寫(xiě)是使用關(guān)中斷好還是使用互斥進(jìn)行保護(hù)呢?

    我想問(wèn)一下,就是我有很多變量會(huì)多線程讀寫(xiě)操作,有一些會(huì)比較頻繁,我讀寫(xiě)的時(shí)候是使用中斷去保護(hù)還是增加互斥量去保護(hù)。 1.如果加互斥量,當(dāng)前低優(yōu)先級(jí)
    發(fā)表于 05-05 14:14

    了解Linux線程線程同步

    進(jìn)程通信IPC,線程可以直接讀寫(xiě)進(jìn)程數(shù)據(jù)段(如全局變量)來(lái)進(jìn)行通信——需要進(jìn)程同步和互斥手段的輔助,以保證數(shù)據(jù)的一致性。
    發(fā)表于 04-23 14:23 ?725次閱讀
    了解<b class='flag-5'>Linux</b>多<b class='flag-5'>線程</b>及<b class='flag-5'>線程</b><b class='flag-5'>間</b>同步

    詳談Linux操作系統(tǒng)的三種狀態(tài)的讀寫(xiě)

    讀寫(xiě)是另一種實(shí)現(xiàn)線程同步的方式。與互斥量類(lèi)似,但讀寫(xiě)將操作分為讀、寫(xiě)兩種方式,可以多個(gè)
    的頭像 發(fā)表于 09-27 14:57 ?3113次閱讀

    詳談Linux操作系統(tǒng)編程的條件變量

    條件變量是用來(lái)等待線程而不是上鎖的,條件變量通常和互斥一起使用。
    的頭像 發(fā)表于 09-27 15:23 ?1993次閱讀
    詳談<b class='flag-5'>Linux</b>操作系統(tǒng)編程的<b class='flag-5'>條件</b><b class='flag-5'>變量</b>

    Linux下線程通訊--互斥

    互斥是一種簡(jiǎn)單的加鎖的方法來(lái)控制對(duì)共享資源的存取,當(dāng)多個(gè)線程訪問(wèn)公共資源時(shí),為了保證同一時(shí)刻只有一個(gè)線程獨(dú)占資源,就可以通過(guò)互斥加以限制,在一個(gè)時(shí)刻只能有一個(gè)
    的頭像 發(fā)表于 08-24 15:53 ?1958次閱讀
    <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線程條件變量是什么意思

    條件變量 條件變量用于自動(dòng)阻塞線程,直到某個(gè)特定事件發(fā)生或某個(gè)條件滿足為止,通常情況下,
    的頭像 發(fā)表于 07-21 11:18 ?517次閱讀

    讀寫(xiě)的實(shí)現(xiàn)原理規(guī)則

    讀寫(xiě) 互斥或自旋要么是加鎖狀態(tài)、要么是不加鎖狀態(tài),而且一次只有一個(gè)線程可以對(duì)其加鎖。 讀寫(xiě)
    的頭像 發(fā)表于 07-21 11:21 ?904次閱讀
    <b class='flag-5'>讀寫(xiě)</b><b class='flag-5'>鎖</b>的實(shí)現(xiàn)原理規(guī)則

    互斥條件變量的使用

    本文主要分為三個(gè)部分: 第一部分簡(jiǎn)要介紹線程的概念及其使用 第二部分主要介紹互斥條件變量的使用(重點(diǎn)探討pthread_cond_wait) 第三部分參考運(yùn)行IBM的多
    的頭像 發(fā)表于 11-10 14:51 ?611次閱讀
    互斥<b class='flag-5'>鎖</b>及<b class='flag-5'>條件</b><b class='flag-5'>變量</b>的使用
    RM新时代网站-首页