【Linux系統編程】讀寫鎖

00. 目錄

01. 讀寫鎖概述

當有一個線程已經持有互斥鎖時,互斥鎖將所有試圖進入臨界區的線程都阻塞住。但是考慮一種情形,當前持有互斥鎖的線程只是要讀訪問共享資源,而同時有其它幾個線程也想讀取這個共享資源,但是由於互斥鎖的排它性,所有其它線程都無法獲取鎖,也就無法讀訪問共享資源了,但是實際上多個線程同時讀訪問共享資源並不會導致問題。

在對數據的讀寫操作中,更多的是讀操作,寫操作較少,例如對數據庫數據的讀寫應用。爲了滿足當前能夠允許多個讀出,但只允許一個寫入的需求,線程提供了讀寫鎖來實現。

讀寫鎖的特點如下:

1)如果有其它線程讀數據,則允許其它線程執行讀操作,但不允許寫操作。

2)如果有其它線程寫數據,則其它線程都不允許讀、寫操作。

讀寫鎖分爲讀鎖寫鎖,規則如下:

1)如果某線程申請了讀鎖,其它線程可以再申請讀鎖,但不能申請寫鎖。

2)如果某線程申請了寫鎖,其它線程不能申請讀鎖,也不能申請寫鎖。

POSIX 定義的讀寫鎖的數據類型是: pthread_rwlock_t

02. 讀寫鎖函數

2.1 讀寫鎖初始化

#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
	const pthread_rwlockattr_t *restrict attr);
功能:
	用來初始化 rwlock 所指向的讀寫鎖。

參數:
	rwlock:指向要初始化的讀寫鎖指針。
	attr:讀寫鎖的屬性指針。如果 attr 爲 NULL 則會使用默認的屬性初始化讀寫鎖,否則使用指定的 attr 
		  初始化讀寫鎖。

	可以使用宏 PTHREAD_RWLOCK_INITIALIZER 靜態初始化讀寫鎖,比如:
	pthread_rwlock_t my_rwlock = PTHREAD_RWLOCK_INITIALIZER;

	這種方法等價於使用 NULL 指定的 attr 參數調用 pthread_rwlock_init() 來完成動態初始化,
	不同之處在於PTHREAD_RWLOCK_INITIALIZER 宏不進行錯誤檢查。

返回值:
	成功:0,讀寫鎖的狀態將成爲已初始化和已解鎖。
	失敗:非 0 錯誤碼。

2.2 讀寫鎖銷燬

#include <pthread.h>

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
功能:
	用於銷燬一個讀寫鎖,並釋放所有相關聯的資源(所謂的所有指的是由 pthread_rwlock_init() 自動
	申請的資源) 。
參數:
	rwlock:讀寫鎖指針。
返回值:
	成功:0
	失敗:非 0 錯誤碼

2.3 申請讀鎖

#include <pthread.h>

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
功能:
	以阻塞方式在讀寫鎖上獲取讀鎖(讀鎖定)。
	如果沒有寫者持有該鎖,並且沒有寫者阻塞在該鎖上,則調用線程會獲取讀鎖。
	如果調用線程未獲取讀鎖,則它將阻塞直到它獲取了該鎖。一個線程可以在一個讀寫鎖上多次執行讀鎖定。
	線程可以成功調用 pthread_rwlock_rdlock() 函數 n 次,但是之後該線程必須調用 
	pthread_rwlock_unlock() 函數 n 次才能解除鎖定。
參數:
	rwlock:讀寫鎖指針。
返回值:
	成功:0
	失敗:非 0 錯誤碼

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
	用於嘗試以非阻塞的方式來在讀寫鎖上獲取讀鎖。
	如果有任何的寫者持有該鎖或有寫者阻塞在該讀寫鎖上,則立即失敗返回。

2.4 申請寫鎖

#include <pthread.h>

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
功能:
	在讀寫鎖上獲取寫鎖(寫鎖定)。
	如果沒有寫者持有該鎖,並且沒有寫者讀者持有該鎖,則調用線程會獲取寫鎖。
	如果調用線程未獲取寫鎖,則它將阻塞直到它獲取了該鎖。
參數:
	rwlock:讀寫鎖指針。
返回值:
	成功:0
	失敗:非 0 錯誤碼

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
	用於嘗試以非阻塞的方式來在讀寫鎖上獲取寫鎖。
	如果有任何的讀者或寫者持有該鎖,則立即失敗返回。

2.5 釋放讀寫鎖

#include <pthread.h>

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
功能:
	無論是讀鎖或寫鎖,都可以通過此函數解鎖。
參數:
	rwlock:讀寫鎖指針。
返回值:
	成功:0
	失敗:非 0 錯誤碼

03. 讀寫鎖應用示例

下面是一個使用讀寫鎖來實現 4 個線程讀寫一段數據是實例。在此示例程序中,共創建了 4 個線程,其中兩個線程用來寫入數據,兩個線程用來讀取數據。當某個線程讀操作時,其他線程允許讀操作,卻不允許寫操作;當某個線程寫操作時,其它線程都不允許讀或寫操作。

參考代碼如下:

#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);
	}
}
 
//寫操作,其它線程都不允許讀或寫操作
void *fun3(void *arg)
{
	while(1)
	{
		
		pthread_rwlock_wrlock(&rwlock);
		num++;
		printf("write thread first\n");
		pthread_rwlock_unlock(&rwlock);
		sleep(2);
	}
}
 
//寫操作,其它線程都不允許讀或寫操作
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);//初始化一個讀寫鎖
	
	//創建線程
	pthread_create(&ptd1, NULL, fun1, NULL);
	pthread_create(&ptd2, NULL, fun2, NULL);
	pthread_create(&ptd3, NULL, fun3, NULL);
	pthread_create(&ptd4, NULL, fun4, NULL);
	
	//等待線程結束,回收其資源
	pthread_join(ptd1,NULL);
	pthread_join(ptd2,NULL);
	pthread_join(ptd3,NULL);
	pthread_join(ptd4,NULL);
	
	pthread_rwlock_destroy(&rwlock);//銷燬讀寫鎖
	
	return 0;
}

測試結果:

deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ gcc 1.c -pthread 
deng@itcast:/mnt/hgfs/LinuxHome/code.bak2$ ./a.out 
read num first===1
read num second===1
write thread first
write thread second
write thread second
read num first===4
read num second===4
write thread first
write thread second
read num first===6
read num first===6
write thread second
read num second===7
write thread first
read num first===8
write thread second
write thread second
read num first===10
read num second===10
write thread first
read num first===11
write thread second
write thread second
read num first===13
read num second===13
write thread first
write thread second
read num first===15
read num first===15
write thread second

04. 附錄

發佈了640 篇原創文章 · 獲贊 2484 · 訪問量 84萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章