Linux線程同步之讀寫鎖(rwlock)
讀寫鎖和互斥量(互斥鎖)很類似,是另一種線程同步機制,但不屬于POSIX標準,可以用來同步同一進程中的各個線程。當然如果一個讀寫鎖存放在多個進程共享的某個內存區中,那么還可以用來進行進程間的同步,
和互斥量不同的是:互斥量會把試圖進入已保護的臨界區的線程都阻塞;然而讀寫鎖會視當前進入臨界區的線程和請求進入臨界區的線程的屬性來判斷是否允許線程進入。
相對互斥量只有加鎖和不加鎖兩種狀態,讀寫鎖有三種狀態:讀模式下的加鎖,寫模式下的加鎖,不加鎖。
讀寫鎖的使用規則:
● 只要沒有寫模式下的加鎖,任意線程都可以進行讀模式下的加鎖;
● 只有讀寫鎖處于不加鎖狀態時,才能進行寫模式下的加鎖;
讀寫鎖也稱為共享-獨占(shared-exclusive)鎖,當讀寫鎖以讀模式加鎖時,它是以共享模式鎖住,當以寫模式加鎖時,它是以獨占模式鎖住。讀寫鎖非常適合讀數據的頻率遠大于寫數據的頻率從的應用中。這樣可以在任何時刻運行多個讀線程并發的執行,給程序帶來了更高的并發度。
需要提到的是:讀寫鎖到目前為止仍然不是屬于POSIX標準,本文討論的讀寫鎖函數都是有Open Group定義的的。例如下面是在我機器上,編譯器是gcc version 4.4.6,關于讀寫鎖的定義是包含在預處理命令中的:
#if defined __USE_UNIX98 || defined __USE_XOPEN2K ... 讀寫鎖相關函數聲明... #endif |
1、讀寫鎖的初始化和銷毀
/* Initialize read-write lock */ /* Destroy read-write lock */ 返回值:成功返回0,否則返回錯誤代碼 |
上面兩個函數分別由于讀寫鎖的初始化和銷毀。和互斥量,條件變量一樣,如果讀寫鎖是靜態分配的,可以通過常量進行初始化,如下:
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; |
也可以通過pthread_rwlock_init()進行初始化。對于動態分配的讀寫鎖由于不能直接賦值進行初始化,只能通過這種方式進行初始化。pthread_rwlock_init()第二個參數是讀寫鎖的屬性,如果采用默認屬性,可以傳入空指針NULL。
那么當不在需要使用時及釋放(自動或者手動)讀寫鎖占用的內存之前,需要調用pthread_rwlock_destroy()進行銷毀讀寫鎖占用的資源。
2、互斥鎖的屬性設置
/* 初始化讀寫鎖屬性對象 */ /* 銷毀讀寫鎖屬性對象 */ /* 獲取讀寫鎖屬性對象在進程間共享與否的標識*/ /* 設置讀寫鎖屬性對象,標識在進程間共享與否 */ 返回值:成功返回0,否則返回錯誤代碼 |
這個屬性設置和互斥量的基本一樣,具體可以參考互斥量的設置互斥量的屬性設置
3、互斥鎖的使用
/* 讀模式下加鎖 */ /* 非阻塞的讀模式下加鎖 */ # ifdef __USE_XOPEN2K /* 寫模式下加鎖 */ /* 非阻塞的寫模式下加鎖 */ # ifdef __USE_XOPEN2K /* 解鎖 */ 返回值:成功返回0,否則返回錯誤代碼 |
(1)pthread_rwlock_rdlock()系列函數
pthread_rwlock_rdlock()用于以讀模式即共享模式獲取讀寫鎖,如果讀寫鎖已經被某個線程以讀模式占用,那么調用線程就被阻塞。在實現讀寫鎖的時候可以對共享模式下鎖的數量進行限制(目前不知如何限制)。
pthread_rwlock_tryrdlock()和pthread_rwlock_rdlock()的唯一區別就是,在無法獲取讀寫鎖的時候,調用線程不會阻塞,會立即返回,并返回錯誤代碼EBUSY。
pthread_rwlock_timedrdlock()是限時等待讀模式加鎖,時間參數struct timespec * __restrict __abstime也是絕對時間,和條件變量的pthread_cond_timedwait()使用基本一致,具體可以參考pthread_cond_timedwait() 3條件變量的使用
(2)pthread_rwlock_wrlock()系列函數
pthread_rwlock_wrlock()用于寫模式即獨占模式獲取讀寫鎖,如果讀寫鎖已經被其他線程占用,不論是以共享模式還是獨占模式占用,調用線程都會進入阻塞狀態。
pthread_rwlock_trywrlock()在無法獲取讀寫鎖的時候,調用線程不會進入睡眠,會立即返回,并返回錯誤代碼EBUSY。
pthread_rwlock_timedwrlock()是限時等待寫模式加鎖,也和條件變量的pthread_cond_timedwait()使用基本一致,具體可以參考pthread_cond_timedwait()3條件變量的使用。
(3)pthread_rwlock_unlock()
無論以共享模式還是獨占模式獲得的讀寫鎖,都可以通過調用pthread_rwlock_unlock()函數進行釋放該讀寫鎖。
下面是測試代碼:
#include <iostream> #include <unistd.h> using namespace std; struct{ void * produce(void *ptr) sleep(1); void * consume1(void *ptr) ++i; void * consume2(void *ptr) ++i; int main() pthread_create(&tid1, NULL, produce, NULL); void *retVal; pthread_join(tid1, &retVal); return 0; |
測試結果如下:
consume1:0 consume2:0 consume2:0 consume1:1 consume2:1 consume1:2 consume2:2 consume1:3 consume2:3 consume1:4 |
如果把consume1的解鎖注釋掉,如下:
void * consume1(void *ptr) ++i; |
程序的執行結果如下:
consume1:0 consume2:0 consume2:0 consume1:0 consume2:0 consume1:0 consume2:0 consume1:0 consume2:0 consume1:0 |
從執行結果可以看出Open Group提供的讀寫鎖函數是優先考慮等待讀模式占用鎖的線程,這種實現的一個很大缺陷就是出現寫入線程餓死的情況。
posted on 2013-06-28 10:29 順其自然EVO 閱讀(3195) 評論(0) 編輯 收藏 所屬分類: linux