1. 程式人生 > >【Linux】讀寫者模型-讀寫鎖

【Linux】讀寫者模型-讀寫鎖

在編寫多執行緒的時候,有⼀種情況是⼗分常⻅的。那就是,有些公共資料修改的機會⽐較少。相⽐較改寫,它們讀的機會反⽽⾼的多。通常⽽⾔,在讀的過程中,往往伴隨著查詢的操作,中間耗時很⻓。給這種程式碼段加鎖,會極⼤地降低我們程式的效率。那麼有沒有⼀種⽅法,可以專⻔處理這種多讀少寫的情況呢? 有,那就是讀寫鎖。讀寫鎖本質上是⼀種⾃旋鎖。

寫互斥,讀共享。寫的時候別人不能寫也不能讀,但是大家可以一起讀取。加寫鎖的時候判斷write是否大於0;如果大於零代表有人加寫鎖,將阻塞,否則write計數器+1;加寫鎖的時候判斷read是否大於0;如果大於零代表有人加讀鎖,將阻塞,否則write計數器+1;加讀鎖的時候判斷write是否大於0;如果大於零代表有人加寫鎖,將阻塞,否則read計數器+1;

讀寫鎖,預設加讀鎖優先,但這種情況會造成飢餓情況。因此使用的時候需要重新設定讀寫鎖為加寫鎖優先(等待兩個計數都為0;並且拒絕在這期間其他加讀鎖的操作)。

讀寫鎖是使用自旋鎖實現的,條件不滿足一直迴圈判斷,耗費CPU資源較多。自旋鎖是不斷髮起加鎖請求。

使用場景:

1.寫的操作少,讀的操作多。

2.不管讀操作還是寫操作,操作時間都比較短。

設定讀寫優先

//初始化讀寫鎖屬性
pthread_rwlockattr_init(pthread_rwlockattr_t* attr);


//設定寫鎖優先
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr, int pref);
pref 共有3種選擇

PTHREAD_RWLOCK_PREFER_READER_NP (預設設定)住著優先,可能會導致寫著飢餓情況

PTHREAD_RWLOCK_PREFER_WRITER_NP   寫著優先,目前有bug,導致表現行為和PTHREAD_RWLOCK_PREFER_READER_NP一致

PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP    寫著優先,但寫著不能遞迴枷鎖


//釋放讀寫鎖屬性
pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);

初始化

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
rwlock:讀寫鎖變數
attr:   讀寫鎖屬性
返回值:失敗:錯誤編號   成功: 0

銷燬

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

加讀鎖

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

加寫鎖

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

解鎖

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

演示預設讀鎖優先

#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
using namespace std;

pthread_rwlock_t rwlock;
void* reader(void* arg)
{
    cout << "start read" << endl;
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        cout << "read lock!!" <<pthread_self() << endl;
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
    }
    return NULL;
}

void* writer(void* arg)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        cout << "------write lock!!" << endl;
        sleep(3);
        pthread_rwlock_unlock(&rwlock);
        cout << "------write over" << endl;
    }
    return NULL;
}

int main()
{
    pthread_t rtid[4], wtid;
    int i;
    pthread_rwlock_init(&rwlock, NULL);
    for(i = 0; i < 4; ++i)
    {
        pthread_create(&rtid[i], NULL, reader, NULL);
    }

    pthread_create(&wtid, NULL, writer, NULL);

    pthread_join(wtid, NULL);

    for(i = 0; i < 4; ++i)
    {
        pthread_join(rtid[1], NULL);
    }


    pthread_rwlock_destroy(&rwlock);
    return 0;
}

很明顯,四個讀鎖優先加鎖,導致寫鎖一直得不到時間片,所以加不上。

設定&測試寫鎖優先

#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
using namespace std;

pthread_rwlock_t rwlock;
void* reader(void* arg)
{
    cout << "start read" << endl;
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        cout << "read lock!!" <<pthread_self() << endl;
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
    }
    return NULL;
}

void* writer(void* arg)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        cout << "------write lock!!" << endl;
        sleep(3);
        pthread_rwlock_unlock(&rwlock);
        cout << "------write over" << endl;
    }
    return NULL;
}

int main()
{
    pthread_t rtid[4], wtid;

    //設定寫鎖優先
    pthread_rwlockattr_t attr;
    //初始化讀寫鎖屬性
    pthread_rwlockattr_init(&attr);
    //設定寫鎖優先
    pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
    int i;
    pthread_rwlock_init(&rwlock, &attr);
    //釋放讀寫鎖屬性
    pthread_rwlockattr_destroy(&attr);
    for(i = 0; i < 4; ++i)
    {
        pthread_create(&rtid[i], NULL, reader, NULL);
    }

    pthread_create(&wtid, NULL, writer, NULL);

    pthread_join(wtid, NULL);

    for(i = 0; i < 4; ++i)
    {
        pthread_join(rtid[1], NULL);
    }


    pthread_rwlock_destroy(&rwlock);
    return 0;
}