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ú)占鎖。
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);
}
}
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)題。
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;
}
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)行效果:
審核編輯 黃昊宇
-
Linux
+關(guān)注
關(guān)注
87文章
11292瀏覽量
209318 -
線程
+關(guān)注
關(guān)注
0文章
504瀏覽量
19675
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論