讀者寫者模型(讀寫鎖)
在編寫多線程時,有可能會出現有些公共區域的數據修改的機會比較少,但是讀的機會反而很多,也就是說寫者少,讀者多。那麼在讀的過程中往往伴隨着查找的操作,耗時較長,如果給這種代碼加鎖的話,會導致效率的降低,因此讀寫鎖就是針對多讀少寫的情況。
當前鎖狀態 | 讀鎖請求 | 寫鎖請求 |
---|---|---|
無鎖 | 可以 | 可以 |
讀鎖 | 可以 | 阻塞 |
寫鎖 | 阻塞 | 阻塞 |
這裏默認是讀鎖優先的,因爲讀者非常的多,但是這樣也就會導致寫鎖的飢餓問題。
讀者寫者模型和生產者消費者模型的區別?
讀者寫者模型和生產者消費者模型最大的區別就是生產者生產數據之後,消費者就會將數據消費掉,其他消費者則無法享受該數據。而讀者寫者模型中寫者進行數據的寫入時,所有的讀者都可以享受該數據,直到寫者再次寫入。
讀者寫者模型中的三重關係?
寫者和寫者的關係:互斥
讀者和讀者的關係:共享
讀者和寫者的關係:互斥和同步(當寫者進行數據寫入時,讀者不可以進行數據的讀取,當讀者進行數據的讀取時,寫者不可以進行數據的寫入,同時讀者必須等待寫者把數據寫完纔可以進行數據的寫入)
既然讀讀不互斥,爲何還要加讀鎖?
答: 如果只是讀,是不需要加鎖的,加鎖本身就有性能上的損耗
如果讀可以不是最新數據,也不需要加鎖
如果讀必須是最新數據,必須加讀寫鎖
讀寫鎖相較於互斥鎖的優點僅僅是允許讀讀的併發,除此之外並無其他。
讀寫鎖相關函數
讀寫鎖的初始化(pthread_rwlock_init)
功能: 初始化讀寫鎖
#include<pthread.h> int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthred_rwlockattr_t *restrict attr);
參數說明:
rwlock: 是要進行初始化的讀寫鎖
attr:是rwlock的屬性,此參數一般不關注,可設爲NULL
讀寫鎖的銷燬(pthread_rwlock_destroy)
功能: 銷燬初始化的鎖
#include<pthread.h> int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
參數說明:
rwlock: 是需要進行銷燬的鎖
加讀鎖(pthread_rdlock_lock)
pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);
加寫鎖(pthread_wrlock_lock)
pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);
讀鎖寫鎖的解鎖(pthread_rwlock_unlock)
pthread_rwlock_unlock(pthread_rwlock_t* rwlock);
讀者寫者模型示例代碼
運行結果:
讓讀者每隔100微秒讀一次,讓寫者每隔90微秒寫一次,時間間隔很短,有五個讀者,因此能看到讀者讀數據較爲頻繁。
在這裏的代碼其實不是很符合讀者寫者模型,因爲實際上讀者寫者模型中讀者可能會讀幾分鐘一直都在讀,這裏我們只是爲了看到現象而加入了usleep函數來控制讀者寫者的速度。
這裏運行速度太快啦(╯°Д°)╯!作者手速跟不上,我就截取小片段遼(✧◡✧)!
代碼如下:
1 #include <iostream>
2 #include <pthread.h>
3 #include <unistd.h>
4 int data=0;
5 pthread_rwlock_t rwlock;
6 void *reader(void *arg)
7 {
8 while(1)
9 {
10 pthread_rwlock_rdlock(&rwlock);
11 std::cout<<"reader down:"<<data<<std::endl;
12 pthread_rwlock_unlock(&rwlock);
13 usleep(100);
14 }
15 }
16 void *writer(void *arg)
17 {
18 while(1)
19 {
20 pthread_rwlock_wrlock(&rwlock);
21 std::cout<<"writer down:"<<++data<<std::endl;
22 pthread_rwlock_unlock(&rwlock);
23 usleep(90);
24 }
25 }
26 int main()
27 {
28 pthread_rwlock_init(&rwlock,NULL);
29 pthread_t r[5],w;
30 pthread_create(&r[0],NULL,reader,NULL);
31 pthread_create(&r[1],NULL,reader,NULL);
32 pthread_create(&r[2],NULL,reader,NULL);
33 pthread_create(&r[3],NULL,reader,NULL);
34 pthread_create(&r[4],NULL,reader,NULL);
35 pthread_create(&w,NULL,writer,NULL);
36
37 int i=0;
38 for(i=0;i<5;i++)
39 {
40 pthread_join(r[i],NULL);
41 }
42 pthread_join(w,NULL);
43 pthread_rwlock_destroy(&rwlock);
44 return 0;
45 }