讀寫鎖機制


  在以前的一篇博文Linux多線程編程初探中,只提到了用於線程同步的互斥鎖、條件變量,而沒有提及讀寫鎖(read-write lock)。

  本文主要整理自以下文章:

  讀寫鎖(read-write lock)機制-----多線程同步問題的解決

  請用普通的互斥鎖編程實現一個讀寫鎖

讀寫鎖

  讀寫鎖比mutex有更高的適用性,可以多個線程同時占用讀模式的讀寫鎖,但是只能一個線程占用寫模式的讀寫鎖。

  1)當讀寫鎖是寫加鎖狀態時, 在這個鎖被解鎖之前, 所有試圖對這個鎖加鎖的線程都會被阻塞.

  2)當讀寫鎖在讀加鎖狀態時, 所有試圖以讀模式對它進行加鎖的線程都可以得到訪問權,但是以寫模式對它進行枷鎖的線程將阻塞;

  3)當讀寫鎖在讀模式鎖狀態時, 如果有另外線程試圖以寫模式加鎖讀寫鎖通常會阻塞隨后的讀模式鎖請求, 這樣可以避免讀模式鎖長期占用, 而等待的寫模式鎖請求長期阻塞;

  這種鎖適用對數據結構進行讀的次數比寫的次數多的情況

讀寫鎖API

初始化和銷毀

  對於讀寫鎖變量的初始化可以有兩種方式,一種是通過給一個靜態分配的讀寫鎖賦予常值PTHREAD_RWLOCK_INITIALIZER來初始化它,另一種方法就是通過調用pthread_rwlock_init()來動態的初始化。而當某個線程不再需要讀寫鎖的時候,可以通過調用pthread_rwlock_destroy來銷毀該鎖。函數原型如下:

#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);
// 成功則返回0, 出錯則返回錯誤編號.

  在釋放某個讀寫鎖占用的內存之前,要先通過pthread_rwlock_destroy對讀寫鎖進行清理,釋放由pthread_rwlock_init所分配的資源。在初始化某個讀寫鎖的時候,如果屬性指針attr是個空指針的話,表示默認的屬性;如果想要使用非默認屬性,則要使用到下面的兩個函數:

#include 
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockatttr_t *attr);
// 成功返回0,出錯則返回錯誤碼。

  這里還需要說明的是,當初始化讀寫鎖完畢以后呢,該鎖就處於一個非鎖定狀態。數據類型為pthread_rwlockattr_t的某個屬性對象一旦初始化了,就可以通過不同的函數調用來啟用或者是禁用某個特定的屬性。

讀加鎖和寫加鎖

  讀寫鎖的數據類型是pthread_rwlock_t,如果這個數據類型中的某個變量是靜態分配的,那么可以通過給它賦予常值PTHREAD_RWLOCK_INITIALIZAR來初始化它。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);
// 成功則返回0, 出錯則返回錯誤編號.

  要注意的是其中獲取鎖的兩個函數的操作都是阻塞操作,也就是說獲取不到鎖的話,那么調用線程不是立即返回,而是阻塞執行。有寫情況下,這種阻塞式的獲取所得方式可能不是很適用,所以,接下來引入兩個采用非阻塞方式獲取讀寫鎖的函數pthread_rwlock_tryrdlock()和pthread_rwlock_trywrlock(),非阻塞方式下獲取鎖的時候,如果不能馬上獲取到,就會立即返回一個EBUSY錯誤,而不是把調用線程投入到睡眠等待。函數原型如下:

#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
// 成功則返回0, 出錯則返回錯誤編號.

用互斥鎖實現讀寫鎖

  偽代碼如下:

 1 count_mutex = mutex_init();
 2 write_mutex = mutex_init();
 3 read_count = 0;
 4 
 5 void read_lock{
 6     lock(count_mutex);
 7     read_count++;
 8     if (read_count == 1) {
 9         lock(write_mutex);
10     }
11     unlock(count_mutex);
12 }
13 
14 void read_unlock{
15     lock(count_mutex);
16     read_count--;
17     if (read_count == 0) {
18         unlock(write_mutex);
19     }
20     unlock(count_mutex);
21 }
22 
23 void write_lock{
24     lock(write_mutex);
25 }
26 
27 void write_unlock{
28     unlock(write_mutex);
29 }

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM