当前位置:网站首页>線程同步之讀寫鎖

線程同步之讀寫鎖

2022-06-26 03:57:00 StudyWinter

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

1 讀寫鎖狀態

特別强調: 讀寫鎖只有一把, 但其具備兩種狀態:

1 讀模式下加鎖狀態 (讀鎖);
2 寫模式下加鎖狀態 (寫鎖) 。

2 讀寫鎖特性

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

讀寫鎖也叫共享-獨占鎖。當讀寫鎖以讀模式鎖住時,它是以共享模式鎖住的;當它以寫模式鎖住時,它是以獨占模式鎖住的。 寫獨占、讀共享。讀寫鎖非常適合於對數據結構讀的次數遠大於寫的情况。

主要函數

pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
pthread_rwlock_rdlock(&rwlock);       // try
pthread_rwlock_wrlock(&rwlock);       // try
pthread_rwlock_unlock(&rwlock);
pthread_rwlock_destroy(&rwlock);

以上函數都是成功返回0,失敗返回錯誤號。

(1)pthread_rwlock_init 函數

初始化一把讀寫鎖

pthread_rwlock_t rwlock;

// 方法1
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
                        const pthread_rwlockattr_t *restrict attr);
// 參 2: attr 錶讀寫鎖屬性,通常使用默認屬性, 傳 NULL 即可
// 方法2
rwlock = PTHREAD_RWLOCK_INITIALIZER;

(2)pthread_rwlock_destroy 函數

銷毀一把讀寫鎖

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

(3)pthread_rwlock_rdlock 函數

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

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

(4)pthread_rwlock_wrlock 函數

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

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

(5)pthread_rwlock_unlock 函數

解鎖

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

(6)pthread_rwlock_tryrdlock 函數

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

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

(7)pthread_rwlock_trywrlock函數

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

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

3 兩種死鎖

是使用鎖不恰當導致的現象:

1. 對一個鎖反複lock。
2. 兩個線程,各自持有一把鎖,請求另一把。

4 讀寫鎖案例 

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

// 全局共享資源
int counter;

// 全局讀寫鎖,初始化
pthread_rwlock_t rwlock;

// rwlock = PTHREAD_RWLOCK_INITIALIZER;

// 任務:3個線程不同時寫同一資源,5個線程不同時讀同一資源

// 寫
void *do_write(void *arg)
{
    int t = 0;
    int i = (int)arg;
    int res = 0;

    while (1)
    {
        // 加鎖,寫鎖獨占
        res = pthread_rwlock_wrlock(&rwlock);
        if (res != 0)
        {
            fprintf(stderr, "pthread_rwlock_wrlock error:%s\n", strerror(res));
            exit(1);
        }
        t = counter;
        usleep(10000);
        // 修改就是寫
        printf("------write:%d, %lu, counter = %d, ++counter = %d\n", i, pthread_self(), t, ++counter);

        // 解鎖
        res = pthread_rwlock_unlock(&rwlock);
        if (res != 0)
        {
            fprintf(stderr, "pthread_rwlock_unlock error:%s\n", strerror(res));
            exit(1);
        }
        usleep(10000);
    }
    return NULL;
}

// 讀
void *do_read(void *arg)
{
    int res = 0;
    int i = (int)arg;
    while (1) {
         // 加鎖,讀共享
        res = pthread_rwlock_rdlock(&rwlock);
        if (res != 0)
        {
            fprintf(stderr, "pthread_rwlock_rdlock error:%s\n", strerror(res));
            exit(1);
        }
        usleep(10000);
        // 修改就是寫
        printf("==========================================read:%d, %lu, counter = %d\n", i, pthread_self(), counter);

        // 解鎖
        res = pthread_rwlock_unlock(&rwlock);
        if (res != 0)
        {
            fprintf(stderr, "pthread_rwlock_unlock error:%s\n", strerror(res));
            exit(1);
        }
        usleep(10000);
    }
    return NULL;
}

int main(int argc, char **argv)
{
    int i;
    // 8個線程
    pthread_t tid[8];

    // 初始化讀寫鎖
    int res = pthread_rwlock_init(&rwlock, NULL);
    if (res != 0)
    {
        fprintf(stderr, "pthread_rwlock_init error:%s\n", strerror(res));
        exit(1);
    }

    // 初始化線程
    // 寫線程
    for (i = 0; i < 3; i++)
    {
        res = pthread_create(&tid[i], NULL, do_write, (void *)i);
        if (res != 0)
        {
            fprintf(stderr, "pthread_create write error:%s\n", strerror(res));
            exit(1);
        }
    }

    // 讀線程
    for (i = 3; i < 8; i++)
    {
        res = pthread_create(&tid[i], NULL, do_read, (void *)i);
        if (res != 0)
        {
            fprintf(stderr, "pthread_create read error:%s\n", strerror(res));
            exit(1);
        }
    }

    // 回收子線程
    for (i = 0; i < 8; i++)
    {
        res = pthread_join(tid[i], NULL);
        if (res != 0)
        {
            fprintf(stderr, "pthread_join error:%s\n", strerror(res));
            exit(1);
        }
    }

    // 銷毀讀寫鎖
    res = pthread_rwlock_destroy(&rwlock);
    if (res != 0)
    {
        fprintf(stderr, "pthread_join error:%s\n", strerror(res));
        exit(1);
    }

    return 0;
}

執行

程序輸出飛快,隨便截個圖,如上圖。
由於讀共享,寫獨占。寫鎖優先級高。前面5個read一定先於後面的write到達的,不然write會搶到鎖先進行寫操作。

原网站

版权声明
本文为[StudyWinter]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/177/202206260356298876.html