引言
本文爲第十三篇,線程同步之讀寫鎖,讀寫鎖也是解決線程同步的方法之一,在前邊的兩篇文章中國已經介紹了互斥量和自旋鎖兩種方法。讀寫鎖的原理也和前邊兩種鎖類似,但是讀寫鎖做了一些改進
讀寫鎖
讀寫鎖的改進是從以下幾個點進行考量的,其中最重要的是對臨界資源的考量。在複雜的開發環境中,很可能會出現對臨界資源多讀少寫的情況。比如說一個數據庫中的表,存儲的主要是一些歷史數據,對於這些歷史數據,一般都是進行查詢,很少進行修改,那麼這個存儲歷史數據的表就屬於多讀少寫的臨界資源。對於讀取的時候並不會改變臨界資源的值,如果我們每一次去讀或者寫的時候都給它加鎖,這樣效率是很低的。那麼這個時候就應該考慮是否有效率更高的方法?這個時候就產生了讀寫鎖
讀寫鎖介紹
- 讀寫鎖是一種特殊的自旋鎖
- 允許多個讀者同時訪問資源,以提高讀性能
- 對於寫操作是互斥的(不允許多個寫操作同時訪問同一資源)
關於讀寫鎖的模型
對於讀寫鎖,它允許多個讀者同時去讀取臨界資源,因此下圖中的讀線程1、2、3可以同時讀取臨界資源,但是在讀取的同時,它不會允許寫操作去訪問臨界資源。因爲讀取的時候並不會改變臨界資源,而寫操作可能會改變臨界資源的值,因此在讀寫鎖中讀和寫是互斥的,讀和讀之間是不互斥的
讀寫鎖示例
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<vector>
//臨界資源
int num=0;
//定義讀寫鎖
pthread_rwlock_t relock=PTHREAD_RWLOCK_INITIALIZER;
void *reader(void*){
int times=10000000;
while(times--){
//在讀操作之前加讀鎖
pthread_rwlock_rdlock(&rdlock);
if(times%1000==0){
usleep(10);
}
//釋放讀鎖
pthread_rwlock_unlock(&rdlock);
}
}
void *writer(void*){
int times=10000000;
while(times--){
//加寫鎖
pthread_rwlock_wrlock(&rdlock);
num+=1;
pthread_rwlock_unlock(&rdlock);
}
}
int main()
{
printf("Start in main function.");
//定義三個線程
pthread_t thread1,thread2, thread3;
//兩個執行讀操作,一個執行寫操作
pthread_create(&thread1, NULL, &reader, NULL);
pthread_create(&thread2, NULL, &reader, NULL);
pthread_create(&thread3, NULL, &writer, NULL);
pthread_join(&thread1, NULL);
pthread_join(&thread2, NULL);
pthread_join(&thread3, NULL);
//打印臨界資源的值
printf("Print in main function: num = %d\n", num);
return 0;
}
因爲上邊提到,讀寫鎖對於多讀少寫的情況下,會有很明顯的性能提升的,此時就可以驗證一下,運行上邊使用的讀寫鎖的程序,查看運行時間如下:
現在將讀寫鎖換成互斥量,然後看一下執行時間
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<vector>
//臨界資源
int num=0;
//初始化互斥量
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
//定義讀寫鎖
//pthread_rwlock_t relock=PTHREAD_RWLOCK_INITIALIZER;
void *reader(void*){
int times=10000000;
while(times--){
//在讀操作之前加讀鎖
//pthread_rwlock_rdlock(&rdlock);
pthread_mutex_lock(&mutex);
if(times%1000==0){
usleep(10);
}
//釋放讀鎖
//pthread_rwlock_unlock(&rdlock);
pthread_mutex_unlock(&mutex);
}
}
void *writer(void*){
int times=10000000;
while(times--){
//加寫鎖
//pthread_rwlock_wrlock(&rdlock);
pthread_mutex_lock(&mutex);
num+=1;
//pthread_rwlock_unlock(&rdlock);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
printf("Start in main function.");
//定義三個線程
pthread_t thread1,thread2, thread3;
//兩個執行讀操作,一個執行寫操作
pthread_create(&thread1, NULL, &reader, NULL);
pthread_create(&thread2, NULL, &reader, NULL);
pthread_create(&thread3, NULL, &writer, NULL);
pthread_join(&thread1, NULL);
pthread_join(&thread2, NULL);
pthread_join(&thread3, NULL);
//打印臨界資源的值
printf("Print in main function: num = %d\n", num);
return 0;
}
執行結果:
可以看見,對於多讀少寫的臨界資源,使用讀寫鎖的效率是使用互斥量的大概5倍
PHP中讀寫鎖相關API:https://www.php.net/manual/zh/class.syncreaderwriter.php
在快速變化的技術中尋找不變,纔是一個技術人的核心競爭力。知行合一,理論結合實踐