Linux系統編程 —讀寫鎖rwlock

  • 2020 年 9 月 26 日
  • 筆記

讀寫鎖是另一種實現線程間同步的方式。與互斥量類似,但讀寫鎖將操作分為讀、寫兩種方式,可以多個線程同時佔用讀模式的讀寫鎖,這樣使得讀寫鎖具有更高的並行性。

讀寫鎖的特性為:寫獨佔,讀共享;寫鎖優先級高。對於讀寫鎖,掌握了這12個字就足矣了。

Linux環境下,讀寫鎖具有以下三種狀態:

  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);

函數作用:

初始化一把讀寫鎖

參數說明:

rwlock:傳出參數,調用時應傳&rwlock給該函數;

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);

函數作用:

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

/* 3個線程不定時 "寫" 全局資源,5個線程不定時 "讀" 同一全局資源 */

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

int counter;                          //全局資源
pthread_rwlock_t rwlock;

void *th_write(void *arg)
{
    int t;
    int i = (int)arg;

    while (1) {
        t = counter;
        usleep(1000);

        pthread_rwlock_wrlock(&rwlock);
        printf("=======write %d: %lu: counter=%d ++counter=%d\n", i, pthread_self(), t, ++counter);
        pthread_rwlock_unlock(&rwlock);

        usleep(5000);
    }
    return NULL;
}

void *th_read(void *arg)
{
    int i = (int)arg;

    while (1) {
        pthread_rwlock_rdlock(&rwlock);
        printf("----------------------------read %d: %lu: %d\n", i, pthread_self(), counter);
        pthread_rwlock_unlock(&rwlock);

        usleep(900);
    }
    return NULL;
}

int main(void)
{
    int i;
    pthread_t tid[8];

    pthread_rwlock_init(&rwlock, NULL);

    for (i = 0; i < 3; i++)
        pthread_create(&tid[i], NULL, th_write, (void *)i);

    for (i = 0; i < 5; i++)
        pthread_create(&tid[i+3], NULL, th_read, (void *)i);

    for (i = 0; i < 8; i++)
        pthread_join(tid[i], NULL);

    pthread_rwlock_destroy(&rwlock);            //釋放讀寫瑣

    return 0;
}

更多精彩內容,請關注公眾號良許Linux,公眾內回復1024可免費獲得5T技術資料,包括:Linux,C/C++,Python,樹莓派,嵌入式,Java,人工智能,等等。公眾號內回復進群,邀請您進高手如雲技術交流群。

img


公眾號:良許Linux

有收穫?希望老鐵們來個三連擊,給更多的人看到這篇文章