線程同步與互斥:讀寫鎖 讀寫鎖基本原理: 當(dāng)有一個(gè)線程已經(jīng)持有互斥鎖時(shí),,互斥鎖將所有試圖進(jìn)入臨界區(qū)的線程都阻塞住,。但是考慮一種情形,當(dāng)前持有互斥鎖的線程只是要讀訪問共享資源,,而同時(shí)有其它幾個(gè)線程也想讀取這個(gè)共享資源,,但是由于互斥鎖的排它性,所有其它線程都無法獲取鎖,,也就無法讀訪問共享資源了,,但是實(shí)際上多個(gè)線程同時(shí)讀訪問共享資源并不會導(dǎo)致問題。 在對數(shù)據(jù)的讀寫操作中,,更多的是讀操作,,寫操作較少,例如對數(shù)據(jù)庫數(shù)據(jù)的讀寫應(yīng)用,。為了滿足當(dāng)前能夠允許多個(gè)讀出,,但只允許一個(gè)寫入的需求,線程提供了讀寫鎖來實(shí)現(xiàn),。 讀寫鎖的特點(diǎn)如下: 1)如果有其它線程讀數(shù)據(jù),,則允許其它線程執(zhí)行讀操作,但不允許寫操作。 2)如果有其它線程寫數(shù)據(jù),,則其它線程都不允許讀,、寫操作。 讀寫鎖分為讀鎖和寫鎖,,規(guī)則如下: 1)如果某線程申請了讀鎖,,其它線程可以再申請讀鎖,但不能申請寫鎖,。 2)如果某線程申請了寫鎖,,其它線程不能申請讀鎖,也不能申請寫鎖,。 POSIX 定義的讀寫鎖的數(shù)據(jù)類型是: pthread_rwlock_t,。 讀寫鎖基本操作 以下函數(shù)所需頭文件: #include <pthread.h> 1)初始化讀寫鎖 int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); 功能: 用來初始化 rwlock 所指向的讀寫鎖。 參數(shù): rwlock:指向要初始化的讀寫鎖指針,。 attr:讀寫鎖的屬性指針,。如果 attr 為 NULL 則會使用默認(rèn)的屬性初始化讀寫鎖,否則使用指定的 attr 初始化讀寫鎖,。 可以使用宏 PTHREAD_RWLOCK_INITIALIZER 靜態(tài)初始化讀寫鎖,,比如: pthread_rwlock_t my_rwlock = PTHREAD_RWLOCK_INITIALIZER; 這種方法等價(jià)于使用 NULL 指定的 attr 參數(shù)調(diào)用 pthread_rwlock_init() 來完成動態(tài)初始化,不同之處在于PTHREAD_RWLOCK_INITIALIZER 宏不進(jìn)行錯(cuò)誤檢查,。 返回值: 成功:0,,讀寫鎖的狀態(tài)將成為已初始化和已解鎖。 失?。悍?/span> 0 錯(cuò)誤碼,。 2)申請讀鎖 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock ); 功能: 以阻塞方式在讀寫鎖上獲取讀鎖(讀鎖定)。如果沒有寫者持有該鎖,,并且沒有寫者阻塞在該鎖上,,則調(diào)用線程會獲取讀鎖。如果調(diào)用線程未獲取讀鎖,,則它將阻塞直到它獲取了該鎖,。一個(gè)線程可以在一個(gè)讀寫鎖上多次執(zhí)行讀鎖定。線程可以成功調(diào)用 pthread_rwlock_rdlock() 函數(shù) n 次,,但是之后該線程必須調(diào)用 pthread_rwlock_unlock() 函數(shù) n 次才能解除鎖定,。 參數(shù): rwlock:讀寫鎖指針。 返回值: 成功:0 失?。悍?/span> 0 錯(cuò)誤碼 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); 用于嘗試以非阻塞的方式來在讀寫鎖上獲取讀鎖,。如果有任何的寫者持有該鎖或有寫者阻塞在該讀寫鎖上,則立即失敗返回,。 3)申請寫鎖 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock ); 功能: 在讀寫鎖上獲取寫鎖(寫鎖定),。如果沒有寫者持有該鎖,,并且沒有寫者讀者持有該鎖,則調(diào)用線程會獲取寫鎖,。如果調(diào)用線程未獲取寫鎖,,則它將阻塞直到它獲取了該鎖。 參數(shù): rwlock:讀寫鎖指針,。 返回值: 成功:0 失?。悍?/span> 0 錯(cuò)誤碼 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 用于嘗試以非阻塞的方式來在讀寫鎖上獲取寫鎖。如果有任何的讀者或?qū)懻叱钟性撴i,,則立即失敗返回。 4)解鎖 int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); 功能: 無論是讀鎖或?qū)戞i,,都可以通過此函數(shù)解鎖,。 參數(shù): rwlock:讀寫鎖指針。 返回值: 成功:0 失?。悍?/span> 0 錯(cuò)誤碼 5)銷毀讀寫鎖 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); 功能: 用于銷毀一個(gè)讀寫鎖,,并釋放所有相關(guān)聯(lián)的資源(所謂的所有指的是由 pthread_rwlock_init() 自動申請的資源) 。 參數(shù): rwlock:讀寫鎖指針,。 返回值: 成功:0 失?。悍?/span> 0 錯(cuò)誤碼 讀寫鎖應(yīng)用實(shí)例 下面是一個(gè)使用讀寫鎖來實(shí)現(xiàn) 4 個(gè)線程讀寫一段數(shù)據(jù)是實(shí)例。在此示例程序中,,共創(chuàng)建了 4 個(gè)線程,,其中兩個(gè)線程用來寫入數(shù)據(jù),兩個(gè)線程用來讀取數(shù)據(jù),。當(dāng)某個(gè)線程讀操作時(shí),,其他線程允許讀操作,卻不允許寫操作,;當(dāng)某個(gè)線程寫操作時(shí),,其它線程都不允許讀或?qū)懖僮鳌?/p> 示例代碼如下: #include<stdio.h> #include<unistd.h> #include<pthread.h> pthread_rwlock_t rwlock; //讀寫鎖 int num = 1; //讀操作,其他線程允許讀操作,,卻不允許寫操作 void *fun1(void *arg) { while(1) { pthread_rwlock_rdlock(&rwlock); printf("read num first===%d\n",num); pthread_rwlock_unlock(&rwlock); sleep(1); } } //讀操作,,其他線程允許讀操作,卻不允許寫操作 void *fun2(void *arg) { while(1) { pthread_rwlock_rdlock(&rwlock); printf("read num second===%d\n",num); pthread_rwlock_unlock(&rwlock); sleep(2); } } //寫操作,,其它線程都不允許讀或?qū)懖僮? void *fun3(void *arg) { while(1) { pthread_rwlock_wrlock(&rwlock); num++; printf("write thread first\n"); pthread_rwlock_unlock(&rwlock); sleep(2); } } //寫操作,,其它線程都不允許讀或?qū)懖僮? void *fun4(void *arg) { while(1) { pthread_rwlock_wrlock(&rwlock); num++; printf("write thread second\n"); pthread_rwlock_unlock(&rwlock); sleep(1); } } int main() { pthread_t ptd1, ptd2, ptd3, ptd4; pthread_rwlock_init(&rwlock, NULL);//初始化一個(gè)讀寫鎖 //創(chuàng)建線程 pthread_create(&ptd1, NULL, fun1, NULL); pthread_create(&ptd2, NULL, fun2, NULL); pthread_create(&ptd3, NULL, fun3, NULL); pthread_create(&ptd4, NULL, fun4, NULL); //等待線程結(jié)束,回收其資源 pthread_join(ptd1,NULL); pthread_join(ptd2,NULL); pthread_join(ptd3,NULL); pthread_join(ptd4,NULL); pthread_rwlock_destroy(&rwlock);//銷毀讀寫鎖 return 0; } 運(yùn)行結(jié)果如下: |
|