1. 程式人生 > >Linux:使用讀寫鎖使線程同步

Linux:使用讀寫鎖使線程同步

解釋 -s write des 返回值 沒有 enter red bubuko

基礎與控制原語

讀寫鎖

與互斥量類似,但讀寫鎖允許更高的並行性。其特性為:寫獨占,讀共享。

讀寫鎖狀態:

一把讀寫鎖具備三種狀態:

1. 讀模式下加鎖狀態 (讀鎖)

2. 寫模式下加鎖狀態 (寫鎖)

3. 不加鎖狀態

讀寫鎖特性:

  1. 讀寫鎖是"寫模式加鎖"時, 解鎖前,所有對該鎖加鎖的線程都會被阻塞。
  2. 讀寫鎖是"讀模式加鎖"時, 如果線程以讀模式對其加鎖會成功;如果線程以寫模式加鎖會阻塞。
  3. 讀寫鎖是"讀模式加鎖"時, 既有試圖以寫模式加鎖的線程,也有試圖以讀模式加鎖的線程。那麽讀寫鎖會阻塞隨後的讀模式鎖請求。優先滿足寫模式鎖。讀鎖、寫鎖並行阻塞,寫鎖優先級高

讀寫鎖也叫共享-獨占鎖。當讀寫鎖以讀模式鎖住時,它是以共享模式鎖住的;當它以寫模式鎖住時,它是以獨占模式鎖住的。寫獨占、讀共享。

讀寫鎖非常適合於對數據結構讀的次數遠大於寫的情況。

主要應用函數:

pthread_rwlock_init函數

pthread_rwlock_destroy函數

pthread_rwlock_rdlock函數

pthread_rwlock_wrlock函數

pthread_rwlock_tryrdlock函數

pthread_rwlock_trywrlock函數

pthread_rwlock_unlock函數

以上7 個函數的返回值都是:成功返回0, 失敗直接返回錯誤號。

pthread_rwlock_t類型 用於定義一個讀寫鎖變量。

pthread_rwlock_t rwlock;

pthread_rwlock_init函數

初始化一把讀寫鎖

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

參2:attr表讀寫鎖屬性,通常使用默認屬性,傳NULL即可。

pthread_rwlock_destroy

函數

銷毀一把讀寫鎖

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

pthread_rwlock_rdlock函數

以讀方式請求讀寫鎖。(常簡稱為:請求讀鎖)

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_wrlock函數

以寫方式請求讀寫鎖。(常簡稱為:請求寫鎖)

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

pthread_rwlock_unlock函數

解鎖

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

pthread_rwlock_tryrdlock函數

非阻塞以讀方式請求讀寫鎖(非阻塞請求讀鎖)

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

pthread_rwlock_trywrlock函數

非阻塞以寫方式請求讀寫鎖(非阻塞請求寫鎖)

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

讀寫鎖示例

看如下示例,同時有多個線程對同一全局數據讀、寫操作。

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

#include <unistd.h>

pthread_rwlock_t rwlock;

long int love;

void *pth_wr(void *arg)

{

int i = (int)arg;

while (love <= 520)

{

pthread_rwlock_wrlock(&rwlock);//請求寫鎖

printf("write================全局變量love = %ld, 我是%d號線程。\n", love += 40, i + 1);

pthread_rwlock_unlock(&rwlock);//解鎖

sleep(1);

}

return NULL;

}

void *pth_rd(void *arg)

{

int i = (int)arg;

while (love <= 520)

{

pthread_rwlock_rdlock(&rwlock);//請求讀鎖

printf("全局變量love = %ld, 我是%d號線程。————— - read\n", love, i + 1);

pthread_rwlock_unlock(&rwlock);//解鎖

sleep(1);

}

return NULL;

}

int main(void)

{

pthread_t pth[10];

int i;

pthread_rwlock_init(&rwlock, NULL);

for (i = 0; i != 5; i++)//寫

{

pthread_create(&pth[i], NULL, pth_wr, (void *)i);

}

for (i = 0; i != 5; i++)//讀

{

pthread_create(&pth[5 + i], NULL, pth_rd, (void *)i);

}

while (1)

{

if (love >= 520)

{

for (int j = 0; j != 10; j++)

{

pthread_cancel(pth[j]);//殺死線程

pthread_join(pth[j], NULL);//回收線程

}

break;

}

}

return 0;

}

在裏面,定義了一個全局變量love,當love大於520的時候就停止讀寫並殺死回收線程。讀寫鎖加解鎖的位置和互斥量加解鎖的位置一樣,直接看結果吧:技術分享圖片看,讀數據的時候時一致的,並且讀出來的數據與前面寫進去的數據保持一致,並沒有出現讀出的數據和寫入的數據不一致的情況。雖然線程執行順序沒有順序,但是這並不重要,這只是內核調度和線程爭奪資源的結果,我們關心的不是線程執行順序,而是結果。很明顯,加了鎖之後整整齊齊,是我們想要的效果;當然這樣寫在64位上編譯的時候會有警告:技術分享圖片原因我在上一篇博客上說了的,這裏不再做解釋。

現在我們來看看不加鎖的情況,代碼就是把那些鎖去掉就是。

技術分享圖片這是每次加40的結果;技術分享圖片

這是每次加20的結果,可以看到,次數越多,混亂的情況就越嚴重。

Linux:使用讀寫鎖使線程同步