Linux下線程間通訊---讀寫鎖和條件變量
1.讀寫鎖簡介
讀寫鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。
一次只有一個線程可以占有寫模式的讀寫鎖,但是可以有多個線程同時占有讀模式的讀寫鎖。正是因為這個特性,當讀寫鎖是寫加鎖狀態時,在這個鎖被解鎖之前,所有試圖對這個鎖加鎖的線程都會被阻塞。
當讀寫鎖在讀加鎖狀態時,所有試圖以讀模式對它進行加鎖的線程都可以得到訪問權, 但是如果線程希望以寫模式對此鎖進行加鎖,它必須直到所有的線程釋放鎖。
通常,當讀寫鎖處于讀模式鎖住狀態時,如果有另外線程試圖以寫模式加鎖,讀寫鎖通常會阻塞隨后的讀模式鎖請求,這樣可以避免讀模式鎖長期占用,而等待的寫模式鎖請求長期阻塞。
讀寫鎖適合于對數據結構的讀次數比寫次數多得多的情況。因為,讀模式鎖定時可以共享, 以寫模式鎖住時意味著獨占, 所以讀寫鎖又叫共享-獨占鎖。
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);
}
}
2.條件變量
2.1 條件變量簡介
條件變量是線程可用的一種同步機制,條件變量給多個線程提供了一個回合的場所,條件變量和互斥量一起使用,允許線程以無競爭的方式等待特定的條件發生。
條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。為了防止競爭,條件變量的使用總是和一個互斥鎖結合在一起。
注意:條件變量需要和互斥鎖一起使用。
例如:線程4推送屏幕圖像數據給各個子線程,需要1s推送一次;線程1、2、3獲取推送的數據的頻率則遠小于1s時間,若此類情況使用讀寫鎖則會導致子線程頻繁獲取相同數據幀,極大浪費CPU資源。而使用條件變量則可以有效解決資源浪費問題。
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;
}
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;
}
運行效果:
審核編輯 黃昊宇
-
Linux
+關注
關注
87文章
11304瀏覽量
209483 -
線程
+關注
關注
0文章
504瀏覽量
19682
發布評論請先 登錄
相關推薦
評論