前面介紹的互斥量加鎖要么是鎖狀態,要么就是不加鎖狀態。而且只有一次只有一個線程可以對其加鎖。這樣的目的是為了防止變量被不同的線程修改。但是如果有線程只是想讀而不會去寫的話,這有不會導致變量被修改。但是如果是互斥量加鎖,則讀寫都沒有辦法。這種場景不能使用互斥量,必須使用讀寫鎖。
讀寫鎖可以有3種狀態:
1 讀模式下加鎖狀態
2 寫模式下加鎖狀態
3 不加鎖狀態
一次只有一個線程可以占有寫模式的讀寫鎖,但是多個線程可以同時占有讀模式的讀寫鎖。當讀寫鎖是寫加鎖狀態時,在這個鎖被解鎖之前,所有試圖對這個鎖加鎖的線程都會被阻塞。當讀寫鎖在讀加鎖狀態時,所有試圖以讀模式對它進行加鎖的線程都可以得到訪問權。但是任何希望以寫模式對此鎖進行加鎖的線程都會阻塞。直到所有的線程釋放它們的讀鎖為止。
讀寫鎖非常適合於對數據結構讀的次數大於寫的情況。當讀寫鎖在寫模式下時,它所保護的數據結構就可以被安全地修改,因為一次只有一個線程可以在寫模式下擁有這個鎖。
讀寫鎖也叫做共享互斥鎖。當讀寫鎖是讀模式鎖住的,就可以說是以共享模式鎖住的。當它是寫模式鎖住的時候,就可以說成是以互斥模式鎖住的。
#include <pthread.h>
Int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
Int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
讀寫鎖通過調用pthread_rwlock_init進行初始化。在釋放讀寫鎖占有的內存之前,需要調用pthread_rwlock_destroy做清理工作。如果pthread_rwlock_init為讀寫鎖分配了資源,pthread_rwlock_destroy將釋放這些資源。如果在調用pthread_rwlock_destroy之前就釋放了讀寫鎖占用的內存空間。那么分配給這個鎖的資源就會丟失。
要在讀模式下鎖定讀寫鎖,需要調用pthread_rwlock_rdlock,要在寫模式下鎖定讀寫鎖,需要調用pthread_rwlock_wrlock。不管以何種方式鎖住讀寫鎖。都可以調用pthread_rwlock_unlock進行解鎖。
#include <pthread.h>
Int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
Int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
Int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
來看一個基本的實現例子:
pthread_rwlock_t rwlock;
int data=1;
void readerA(){
while(1){
pthread_rwlock_rdlock(&rwlock);
printf("A讀者讀出:%d\n",data);
pthread_rwlock_unlock(&rwlock);
Sleep(1000);
}
}
void writerB(){
while(1){
pthread_rwlock_wrlock(&rwlock);
data++;
printf("B作者寫入:%d\n",data);
pthread_rwlock_unlock(&rwlock);
Sleep(1000);
}
}
int main()
{
pthread_t t1;
pthread_t t2;
pthread_rwlock_init(&rwlock,NULL);
pthread_create(&t1,NULL,readerA,NULL);
pthread_create(&t2,NULL,writerB,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_rwlock_destroy(&rwlock);
return 0;
}
運行結果如下:可以看到讀者A在讀取數據的時候,data能夠保持原子性。不會被寫的操作給搶占而導致數據不一致。