Linux多線程同步機(jī)制—讀寫鎖(Read-Write Lock)
概述
讀寫鎖(Read-Write Lock)是一種線程同步機(jī)制,用于管理對(duì)共享資源的訪問(wèn)。與互斥鎖(Mutex)不同,讀寫鎖允許多個(gè)線程同時(shí)以讀模式訪問(wèn)共享資源,但只允許一個(gè)線程以寫模式訪問(wèn)資源。這種機(jī)制特別適用于讀操作遠(yuǎn)多于寫操作的場(chǎng)景,可以顯著提高程序的并發(fā)性能。
讀寫鎖原理
讀寫鎖的設(shè)計(jì)基于以下原則:
- 讀操作共享:允許多個(gè)讀線程同時(shí)訪問(wèn)共享資源,只要沒(méi)有寫線程正在訪問(wèn)或等待訪問(wèn)資源。
- 寫操作排他:在任何時(shí)候,只允許一個(gè)寫線程訪問(wèn)共享資源。在寫線程持有鎖期間,所有的讀線程和寫線程都將被阻塞。
讀寫鎖內(nèi)部實(shí)現(xiàn)機(jī)制
讀寫鎖的內(nèi)部實(shí)現(xiàn)通常依賴于一個(gè)或多個(gè)底層鎖和一些額外的狀態(tài)信息。以下是一種常見的實(shí)現(xiàn)方式:
- 計(jì)數(shù)器:用于跟蹤當(dāng)前有多少讀線程正在持有讀鎖。通常,當(dāng)計(jì)數(shù)器大于 0 時(shí),表示有讀線程正在訪問(wèn)資源,此時(shí)不允許寫線程獲取鎖;當(dāng)計(jì)數(shù)器為 0 時(shí),表示沒(méi)有讀線程持有鎖,寫線程可以嘗試獲取鎖。
- 寫鎖標(biāo)志:用于標(biāo)記是否有寫線程正在持有鎖或者有寫線程正在等待獲取鎖。當(dāng)寫鎖標(biāo)志為真時(shí),所有讀線程和寫線程都將被阻塞,直到寫線程釋放鎖。
- 底層互斥鎖和條件變量:讀寫鎖通常會(huì)使用一個(gè)互斥鎖來(lái)保護(hù)其內(nèi)部狀態(tài)(如計(jì)數(shù)器和寫鎖標(biāo)志),以及一個(gè)或多個(gè)條件變量來(lái)實(shí)現(xiàn)線程間的等待和喚醒機(jī)制。
讀寫鎖的典型實(shí)現(xiàn)
在 Linux 和 POSIX 兼容的系統(tǒng)中,讀寫鎖通常通過(guò) pthread_rwlock_t 類型實(shí)現(xiàn)。其內(nèi)部可能包含如下組件:
- 互斥鎖(Mutex):用于保護(hù)讀寫鎖的內(nèi)部狀態(tài),如讀計(jì)數(shù)器和寫鎖狀態(tài)。
- 讀計(jì)數(shù)器(Read Counter):記錄當(dāng)前持有讀鎖的線程數(shù)量。
- 條件變量(Condition Variable):用于實(shí)現(xiàn)線程的等待和通知機(jī)制。通常,會(huì)有兩個(gè)條件變量,一個(gè)用于讀線程,一個(gè)用于寫線程。
當(dāng)線程嘗試獲取讀鎖時(shí),它會(huì)檢查寫鎖狀態(tài)和讀計(jì)數(shù)器,如果當(dāng)前沒(méi)有寫線程正在訪問(wèn)資源,則增加讀計(jì)數(shù)器并允許讀線程繼續(xù);如果存在寫操作,則讀線程將被阻塞,直到寫操作完成。
類似地,當(dāng)線程嘗試獲取寫鎖時(shí),它會(huì)檢查讀計(jì)數(shù)器和寫鎖狀態(tài)。如果當(dāng)前沒(méi)有讀線程和寫線程正在訪問(wèn)資源,則設(shè)置寫鎖狀態(tài)并允許寫線程繼續(xù);如果有讀線程或?qū)懢€程正在訪問(wèn)資源,則寫線程將被阻塞,直到所有讀線程和前一個(gè)寫線程完成操作。
讀寫鎖相關(guān)API
當(dāng)然,我會(huì)補(bǔ)充完整上面的程序,并進(jìn)一步完善API函數(shù)的描述。請(qǐng)注意,由于程序中的線程是無(wú)限循環(huán)的,為了示例的完整性,我將添加一個(gè)全局變量作為退出條件。此外,我將更詳細(xì)地解釋API函數(shù)的使用。
pthread_rwlock_init -- 初始化讀寫鎖
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
- 參數(shù):
rwlock:指向要初始化的讀寫鎖變量的指針。
attr:(可選)指向讀寫鎖屬性的指針。如果傳遞NULL,則使用默認(rèn)屬性。
- 返回值:成功時(shí)返回0,失敗時(shí)返回錯(cuò)誤碼。
pthread_rwlock_destroy -- 銷毀讀寫鎖
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
- 參數(shù):
rwlock:指向要銷毀的讀寫鎖變量的指針。
- 返回值:成功時(shí)返回0,失敗時(shí)返回錯(cuò)誤碼。
pthread_rwlock_rdlock -- 加讀鎖
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- 參數(shù):
rwlock:指向讀寫鎖變量的指針。
- 返回值:成功時(shí)返回0,失敗時(shí)返回錯(cuò)誤碼。如果鎖被其他線程以寫模式持有,則調(diào)用線程將被阻塞。
pthread_rwlock_wrlock -- 加寫鎖
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- 參數(shù):
rwlock:指向讀寫鎖變量的指針。
- 返回值:成功時(shí)返回0,失敗時(shí)返回錯(cuò)誤碼。如果鎖被其他線程以讀模式或?qū)懩J匠钟校瑒t調(diào)用線程將被阻塞。
pthread_rwlock_tryrdlock -- 嘗試加讀鎖(非阻塞)
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- 參數(shù):
rwlock:指向讀寫鎖變量的指針。
- 返回值:成功時(shí)返回0,如果鎖不可用,則返回EBUSY。
C 語(yǔ)言實(shí)現(xiàn)讀寫鎖
一、封裝POSIX 線程庫(kù)的讀寫鎖
封裝 POSIX 線程庫(kù)提供的pthread_rwlock_t類型的讀寫鎖,以及相關(guān)的操作函數(shù)pthread_rwlock_rdlock、pthread_rwlock_wrlock等,即可實(shí)現(xiàn)簡(jiǎn)單的讀寫鎖,無(wú)需自行實(shí)現(xiàn)復(fù)雜的邏輯。以下是一個(gè)簡(jiǎn)單的 C 語(yǔ)言實(shí)現(xiàn)讀寫鎖的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
// 定義讀寫鎖結(jié)構(gòu)體
typedef struct {
pthread_rwlock_t rwlock; // 使用 POSIX 的讀寫鎖
} rwlock_t;
// 定義線程參數(shù)結(jié)構(gòu)體
typedef struct thread_params {
rwlock_t *lock;
int id; // 線程標(biāo)識(shí)符
} thread_params_t;
// 初始化讀寫鎖
void rwlock_init(rwlock_t *lock) {
pthread_rwlock_init(&lock->rwlock, NULL);
}
// 銷毀讀寫鎖并釋放資源
void rwlock_destroy(rwlock_t *lock) {
pthread_rwlock_destroy(&lock->rwlock);
}
// 獲取讀鎖
void rwlock_read_lock(rwlock_t *lock) {
pthread_rwlock_rdlock(&lock->rwlock);
}
// 釋放讀鎖
void rwlock_read_unlock(rwlock_t *lock) {
pthread_rwlock_unlock(&lock->rwlock);
}
// 獲取寫鎖
void rwlock_write_lock(rwlock_t *lock) {
pthread_rwlock_wrlock(&lock->rwlock);
}
// 釋放寫鎖
void rwlock_write_unlock(rwlock_t *lock) {
pthread_rwlock_unlock(&lock->rwlock);
}
// 讀者線程函數(shù)
void *reader(void *arg) {
thread_params_t *params = arg; // 從參數(shù)中獲取線程參數(shù)結(jié)構(gòu)體
int i;
for (i = 0; i < 3; i++) {
rwlock_read_lock(params->lock);
printf("讀者線程 %d: 正在讀取...\n", params->id);
usleep(100000);
rwlock_read_unlock(params->lock);
}
return NULL;
}
// 寫者線程函數(shù)
void *writer(void *arg) {
thread_params_t *params = arg; // 從參數(shù)中獲取線程參數(shù)結(jié)構(gòu)體
int i;
for (i = 0; i < 5; i++) {
rwlock_write_lock(params->lock);
printf("寫者線程 %d: 正在寫入...\n", params->id);
usleep(500000);
rwlock_write_unlock(params->lock);
}
return NULL;
}
int main() {
rwlock_t lock;
rwlock_init(&lock);
pthread_t threads[5];
thread_params_t thread_params[5]; // 定義線程參數(shù)數(shù)組
int i;
// 初始化線程參數(shù)數(shù)組
for (i = 0; i < 5; i++) {
thread_params[i].lock = &lock;
thread_params[i].id = i + 1; // 分配線程標(biāo)識(shí)符
}
// 創(chuàng)建讀者線程
for (i = 0; i < 4; i++) {
pthread_create(&threads[i], NULL, reader, &thread_params[i]);
}
// 創(chuàng)建寫者線程
pthread_create(&threads[4], NULL, writer, &thread_params[4]);
// 加入所有線程,等待它們完成
for (i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
rwlock_destroy(&lock);
return 0;
}
注意:封裝 rwlock_t 結(jié)構(gòu)體的主要原因在于提供一個(gè)清晰、模塊化的接口來(lái)管理和使用讀寫鎖,這帶來(lái)了以下幾方面的優(yōu)勢(shì):
- 封裝細(xì)節(jié):
將讀寫鎖的實(shí)現(xiàn)細(xì)節(jié)封裝在rwlock_t結(jié)構(gòu)體內(nèi),對(duì)外只暴露必要的接口(如初始化、銷毀、讀鎖和寫鎖操作)。這樣做的好處是隱藏了內(nèi)部實(shí)現(xiàn)的復(fù)雜性,外部調(diào)用者只需要關(guān)注如何使用鎖,而不必關(guān)心鎖的具體實(shí)現(xiàn)。
- 類型安全:
使用專門的結(jié)構(gòu)體類型rwlock_t來(lái)表示讀寫鎖,增強(qiáng)了類型安全。這意味著在使用讀寫鎖的地方,編譯器可以檢查是否正確使用了讀寫鎖相關(guān)的函數(shù),避免了類型錯(cuò)誤。
可擴(kuò)展性:
如果將來(lái)需要改變讀寫鎖的實(shí)現(xiàn)方式,比如從使用pthread_rwlock_t切換到另一種鎖機(jī)制,只需修改rwlock_t結(jié)構(gòu)體和相關(guān)操作函數(shù),而無(wú)需修改所有使用讀寫鎖的地方。這大大提高了代碼的可維護(hù)性和可擴(kuò)展性。
代碼組織與重用:
封裝讀寫鎖的操作在一個(gè)獨(dú)立的結(jié)構(gòu)體和一組函數(shù)中,使得代碼更加整潔、有條理。此外,這樣的封裝有利于代碼的重用,如果項(xiàng)目中其他地方也需要使用讀寫鎖,可以直接引用rwlock_t及相關(guān)函數(shù),無(wú)需重復(fù)編寫相同的代碼。
測(cè)試與調(diào)試便利性:
將讀寫鎖的創(chuàng)建、使用和銷毀操作集中在一個(gè)結(jié)構(gòu)體及其相關(guān)函數(shù)中,方便了單元測(cè)試和調(diào)試??梢元?dú)立地測(cè)試讀寫鎖的功能,確保其在各種情況下的正確性。
綜上所述,封裝rwlock_t結(jié)構(gòu)體是軟件工程中一種常見的抽象和封裝機(jī)制,它不僅提高了代碼的可讀性和可維護(hù)性,也增強(qiáng)了系統(tǒng)的靈活性和健壯性。
這個(gè)示例中的關(guān)鍵點(diǎn)詳細(xì)闡述如下:
1. 讀寫鎖結(jié)構(gòu)體定義 (rwlock_t)
- 定義:
typedef struct {
pthread_rwlock_t rwlock; // 使用 POSIX 的讀寫鎖
} rwlock_t;
- 解析:
rwlock_t結(jié)構(gòu)體封裝了一個(gè)pthread_rwlock_t類型的讀寫鎖實(shí)例。
pthread_rwlock_t 是 POSIX 標(biāo)準(zhǔn)中定義的一種高級(jí)鎖機(jī)制,允許同時(shí)存在多個(gè)讀操作,但寫操作是排他的,確保了數(shù)據(jù)在并發(fā)訪問(wèn)時(shí)的一致性。
2. 線程參數(shù)結(jié)構(gòu)體定義 (thread_params_t)
- 定義:
typedef struct thread_params {
rwlock_t *lock;
int id; // 線程標(biāo)識(shí)符
} thread_params_t;
- 解析:
thread_params_t 結(jié)構(gòu)體用于存儲(chǔ)線程運(yùn)行所需的信息,包括指向讀寫鎖的指針和線程的唯一標(biāo)識(shí)符。
這種設(shè)計(jì)允許線程函數(shù)以統(tǒng)一的方式接收參數(shù),增強(qiáng)代碼的可讀性和可維護(hù)性。
3. 讀寫鎖操作函數(shù)
- 初始化與銷毀:
void rwlock_init(rwlock_t *lock);
void rwlock_destroy(rwlock_t *lock);
rwlock_init 負(fù)責(zé)初始化讀寫鎖,確保其處于可用狀態(tài)。
rwlock_destroy 用于清理鎖資源,避免內(nèi)存泄漏。
解析:
- 讀鎖操作:
void rwlock_read_lock(rwlock_t *lock);
void rwlock_read_unlock(rwlock_t *lock);
rwlock_read_lock 獲取讀鎖,允許多個(gè)讀線程同時(shí)訪問(wèn)共享資源。
rwlock_read_unlock 釋放讀鎖,使其他線程有機(jī)會(huì)獲取鎖。
解析:
寫鎖操作:
void rwlock_write_lock(rwlock_t *lock); void rwlock_write_unlock(rwlock_t *lock);
rwlock_write_lock 獲取寫鎖,確保寫操作的排他性,防止數(shù)據(jù)競(jìng)爭(zhēng)。
rwlock_write_unlock 釋放寫鎖,使其他線程可以繼續(xù)執(zhí)行。
解析:
4. 線程函數(shù)
- 讀者線程:
void *reader(void *arg);
讀者線程函數(shù) reader 接收一個(gè) thread_params_t 類型的參數(shù),從中提取讀寫鎖和線程標(biāo)識(shí)符。
線程執(zhí)行多次讀操作,每次讀取前獲取讀鎖,讀取后釋放讀鎖。
解析:
- 寫者線程:
void *writer(void *arg);
寫者線程函數(shù) writer 同樣接收 thread_params_t 類型的參數(shù)。
線程執(zhí)行多次寫操作,每次寫入前獲取寫鎖,寫入后釋放寫鎖。
解析:
5. 主函數(shù) (main)
- 初始化與線程創(chuàng)建:
初始化讀寫鎖。
創(chuàng)建線程參數(shù)數(shù)組,為每個(gè)線程分配唯一標(biāo)識(shí)符和讀寫鎖引用。
使用pthread_create 創(chuàng)建 4 個(gè)讀者線程和 1 個(gè)寫者線程。
- 線程同步與資源清理:
使用 pthread_join 確保所有線程完成后再繼續(xù)執(zhí)行。
調(diào)用 rwlock_destroy 銷毀讀寫鎖,釋放相關(guān)資源。
6. 線程標(biāo)識(shí)符
- 功能:
每個(gè)線程擁有一個(gè)從 1 開始的唯一標(biāo)識(shí)符,便于在日志和調(diào)試信息中區(qū)分不同線程。
7. POSIX讀寫鎖機(jī)制
- 優(yōu)勢(shì):
支持多個(gè)讀線程的同時(shí)訪問(wèn),提高了讀密集型應(yīng)用的并發(fā)性能。
確保寫操作的排他性,避免數(shù)據(jù)損壞,適用于寫操作較少的場(chǎng)景。
8. 線程創(chuàng)建與管理
- 細(xì)節(jié):
使用pthread_create創(chuàng)建線程,傳入線程函數(shù)和參數(shù)。
利用pthread_join等待線程結(jié)束,保證程序的正確性和資源的有序釋放。
9. 資源管理
- 重要性:
通過(guò)初始化和銷毀讀寫鎖,確保了鎖資源的生命周期管理,避免了內(nèi)存泄漏和資源浪費(fèi)。
編譯并執(zhí)行程序,結(jié)果如下:
[root@localhost rwlock]# gcc pthread_rwlock.c -o pthread_rwlock -lpthread
[root@localhost rwlock]# ls
pthread_rwlock pthread_rwlock.c
[root@localhost rwlock]# ./pthread_rwlock
讀者線程 1: 正在讀取...
讀者線程 2: 正在讀取...
讀者線程 3: 正在讀取...
讀者線程 4: 正在讀取...
讀者線程 1: 正在讀取...
讀者線程 2: 正在讀取...
讀者線程 4: 正在讀取...
讀者線程 3: 正在讀取...
讀者線程 1: 正在讀取...
讀者線程 2: 正在讀取...
讀者線程 4: 正在讀取...
讀者線程 3: 正在讀取...
寫者線程 5: 正在寫入...
寫者線程 5: 正在寫入...
寫者線程 5: 正在寫入...
寫者線程 5: 正在寫入...
寫者線程 5: 正在寫入...
通過(guò)深入解析上述代碼和結(jié)果,我們可以更全面地理解基于 POSIX 讀寫鎖的多線程程序設(shè)計(jì)策略,以及如何有效利用鎖機(jī)制來(lái)提高并發(fā)應(yīng)用的性能和可靠性。
二、自定義實(shí)現(xiàn)的典型讀寫鎖
自定義實(shí)現(xiàn)讀寫鎖代碼需要開發(fā)者更深入地理解讀寫鎖的底層實(shí)現(xiàn)原理。完全自行實(shí)現(xiàn)讀寫鎖的邏輯,通過(guò)互斥鎖、條件變量以及自定義的讀計(jì)數(shù)和寫標(biāo)志來(lái)管理讀寫操作的同步。以下是一段 C 語(yǔ)言實(shí)現(xiàn)自定義實(shí)現(xiàn)讀寫鎖的代碼:
#include <pthread.h>
#include <stdio.h>
// 定義讀寫鎖結(jié)構(gòu)體
typedef struct rwlock {
pthread_mutex_t lock; // 互斥鎖,用于保護(hù)讀寫鎖的內(nèi)部狀態(tài)
pthread_cond_t read_cond; // 條件變量,用于讀操作的等待和通知
pthread_cond_t write_cond; // 條件變量,用于寫操作的等待和通知
int read_count; // 讀操作的計(jì)數(shù)
int write_in_progress; // 寫操作是否正在進(jìn)行的標(biāo)志
} rwlock_t;
// 初始化讀寫鎖
void rwlock_init(rwlock_t *rwlock) {
// 初始化互斥鎖
pthread_mutex_init(&rwlock->lock, NULL);
// 初始化讀操作的條件變量
pthread_cond_init(&rwlock->read_cond, NULL);
// 初始化寫操作的條件變量
pthread_cond_init(&rwlock->write_cond, NULL);
// 初始時(shí)讀計(jì)數(shù)為 0
rwlock->read_count = 0;
// 初始時(shí)寫操作未進(jìn)行
rwlock->write_in_progress = 0;
}
// 讀鎖加鎖
void rwlock_read_lock(rwlock_t *rwlock) {
// 獲取互斥鎖
pthread_mutex_lock(&rwlock->lock);
// 若有寫操作正在進(jìn)行,讀線程等待
while (rwlock->write_in_progress) {
pthread_cond_wait(&rwlock->read_cond, &rwlock->lock);
}
// 讀計(jì)數(shù)增加
rwlock->read_count++;
// 釋放互斥鎖
pthread_mutex_unlock(&rwlock->lock);
}
// 讀鎖解鎖
void rwlock_read_unlock(rwlock_t *rwlock) {
// 獲取互斥鎖
pthread_mutex_lock(&rwlock->lock);
// 讀計(jì)數(shù)減少
rwlock->read_count--;
// 若讀計(jì)數(shù)為 0 且無(wú)寫操作正在進(jìn)行,通知寫線程
if (rwlock->read_count == 0 && rwlock->write_in_progress == 0) {
pthread_cond_signal(&rwlock->write_cond);
}
// 釋放互斥鎖
pthread_mutex_unlock(&rwlock->lock);
}
// 寫鎖加鎖
void rwlock_write_lock(rwlock_t *rwlock) {
// 獲取互斥鎖
pthread_mutex_lock(&rwlock->lock);
// 若有讀操作或?qū)懖僮髡谶M(jìn)行,寫線程等待
while (rwlock->read_count > 0 || rwlock->write_in_progress) {
pthread_cond_wait(&rwlock->write_cond, &rwlock->lock);
}
// 標(biāo)記寫操作正在進(jìn)行
rwlock->write_in_progress = 1;
// 釋放互斥鎖
pthread_mutex_unlock(&rwlock->lock);
}
// 寫鎖解鎖
void rwlock_write_unlock(rwlock_t *rwlock) {
// 獲取互斥鎖
pthread_mutex_lock(&rwlock->lock);
// 標(biāo)記寫操作結(jié)束
rwlock->write_in_progress = 0;
// 通知所有等待讀的線程
pthread_cond_broadcast(&rwlock->read_cond);
// 通知等待寫的線程
pthread_cond_signal(&rwlock->write_cond);
// 釋放互斥鎖
pthread_mutex_unlock(&rwlock->lock);
}
// 讀線程的操作函數(shù)
void reader_function(rwlock_t *rwlock) {
rwlock_read_lock(rwlock);
printf("Reader is reading...\n");
rwlock_read_unlock(rwlock);
}
// 寫線程的操作函數(shù)
void writer_function(rwlock_t *rwlock) {
rwlock_write_lock(rwlock);
printf("Writer is writing...\n");
rwlock_write_unlock(rwlock);
}
int main() {
rwlock_t rwlock; // 定義讀寫鎖變量
rwlock_init(&rwlock); // 初始化讀寫鎖
pthread_t reader1, reader2, writer; // 定義線程變量
// 創(chuàng)建讀線程 1
pthread_create(&reader1, NULL, (void *)reader_function, &rwlock);
// 創(chuàng)建讀線程 2
pthread_create(&reader2, NULL, (void *)reader_function, &rwlock);
// 創(chuàng)建寫線程
pthread_create(&writer, NULL, (void *)writer_function, &rwlock);
// 等待讀線程 1 結(jié)束
pthread_join(reader1, NULL);
// 等待讀線程 2 結(jié)束
pthread_join(reader2, NULL);
// 等待寫線程結(jié)束
pthread_join(writer, NULL);
return 0;
}
以下是對(duì)這段代碼的詳細(xì)解析:
1.包含頭文件
#include <pthread.h>:包含了 POSIX 線程庫(kù)的頭文件,用于多線程編程。
#include <stdio.h>:包含了標(biāo)準(zhǔn)輸入輸出頭文件,用于打印輸出。
2.定義讀寫鎖結(jié)構(gòu)體 rwlock_t
pthread_mutex_t lock:用于保護(hù)讀寫鎖內(nèi)部狀態(tài)的互斥鎖。
pthread_cond_t read_cond:用于讀操作等待和通知的條件變量。
pthread_cond_t write_cond:用于寫操作等待和通知的條件變量。
int read_count:記錄讀操作的數(shù)量。
int write_in_progress:標(biāo)志是否有寫操作正在進(jìn)行。
3.函數(shù)定義
rwlock_init 函數(shù):初始化讀寫鎖的各個(gè)成員,包括互斥鎖和條件變量,將讀計(jì)數(shù)設(shè)為0,寫標(biāo)志設(shè)為0。
rwlock_read_lock 函數(shù):獲取讀鎖。先獲取互斥鎖,若有寫操作正在進(jìn)行則等待,然后增加讀計(jì)數(shù),最后釋放互斥鎖。
rwlock_read_unlock 函數(shù):釋放讀鎖。先獲取互斥鎖,減少讀計(jì)數(shù),若讀計(jì)數(shù)為 0 且無(wú)寫操作正在進(jìn)行則通知寫線程,最后釋放互斥鎖。
rwlock_write_lock 函數(shù):獲取寫鎖。先獲取互斥鎖,若有讀操作或?qū)懖僮髡谶M(jìn)行則等待,然后設(shè)置寫標(biāo)志為 1,最后釋放互斥鎖。
rwlock_write_unlock 函數(shù):釋放寫鎖。先獲取互斥鎖,清除寫標(biāo)志,通知所有等待讀的線程和一個(gè)等待寫的線程,最后釋放互斥鎖。
reader_function 函數(shù):讀線程的執(zhí)行函數(shù),獲取讀鎖后打印信息然后釋放讀鎖。
- writer_function 函數(shù):寫線程的執(zhí)行函數(shù),獲取寫鎖后打印信息然后釋放寫鎖。
4.main 函數(shù)
定義讀寫鎖變量 rwlock 并初始化。
定義線程變量 reader1、reader2 和 writer。
創(chuàng)建兩個(gè)讀線程和一個(gè)寫線程,并分別指定執(zhí)行函數(shù)和傳遞讀寫鎖參數(shù)。
使用 pthread_join 等待三個(gè)線程結(jié)束,確保程序不會(huì)提前退出。總的來(lái)說(shuō),這段代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的讀寫鎖機(jī)制,通過(guò)多線程的方式展示了讀線程和寫線程對(duì)共享資源的同步訪問(wèn)。
編譯并執(zhí)行程序,結(jié)果如下:
[root@localhost rwlock]# gcc pthread_rwlock_st.c -o pthread_rwlock_st -lpthread
[root@localhost rwlock]# ls
pthread_rwlock pthread_rwlock.c pthread_rwlock_st pthread_rwlock_st.c
[root@localhost rwlock]# ./pthread_rwlock_st
Reader is reading...
Reader is reading...
Writer is writing...
總結(jié)
讀寫鎖相比于傳統(tǒng)的互斥鎖(mutex)具有更高的并發(fā)性能,特別是在讀操作遠(yuǎn)多于寫操作的場(chǎng)景下。這是因?yàn)樽x寫鎖允許多個(gè)讀線程同時(shí)訪問(wèn)共享資源,從而減少了線程間的等待時(shí)間,提高了系統(tǒng)的整體吞吐量。
然而,讀寫鎖也有其局限性,例如在寫操作頻繁的場(chǎng)景下,由于寫操作的排他性,可能會(huì)導(dǎo)致大量的讀線程被阻塞,降低系統(tǒng)的并發(fā)性能。因此,在設(shè)計(jì)多線程應(yīng)用時(shí),選擇合適的同步機(jī)制是非常重要的。