【Linux】讀寫者模型-讀寫鎖
阿新 • • 發佈:2018-12-30
在編寫多執行緒的時候,有⼀種情況是⼗分常⻅的。那就是,有些公共資料修改的機會⽐較少。相⽐較改寫,它們讀的機會反⽽⾼的多。通常⽽⾔,在讀的過程中,往往伴隨著查詢的操作,中間耗時很⻓。給這種程式碼段加鎖,會極⼤地降低我們程式的效率。那麼有沒有⼀種⽅法,可以專⻔處理這種多讀少寫的情況呢? 有,那就是讀寫鎖。讀寫鎖本質上是⼀種⾃旋鎖。
寫互斥,讀共享。寫的時候別人不能寫也不能讀,但是大家可以一起讀取。加寫鎖的時候判斷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;
}