計算機操作系統基礎(十三)---線程同步之讀寫鎖

引言

本文爲第十三篇,線程同步之讀寫鎖,讀寫鎖也是解決線程同步的方法之一,在前邊的兩篇文章中國已經介紹了互斥量和自旋鎖兩種方法。讀寫鎖的原理也和前邊兩種鎖類似,但是讀寫鎖做了一些改進

讀寫鎖

讀寫鎖的改進是從以下幾個點進行考量的,其中最重要的是對臨界資源的考量。在複雜的開發環境中,很可能會出現對臨界資源多讀少寫的情況。比如說一個數據庫中的表,存儲的主要是一些歷史數據,對於這些歷史數據,一般都是進行查詢,很少進行修改,那麼這個存儲歷史數據的表就屬於多讀少寫的臨界資源。對於讀取的時候並不會改變臨界資源的值,如果我們每一次去讀或者寫的時候都給它加鎖,這樣效率是很低的。那麼這個時候就應該考慮是否有效率更高的方法?這個時候就產生了讀寫鎖

讀寫鎖介紹

  • 讀寫鎖是一種特殊的自旋鎖
  • 允許多個讀者同時訪問資源,以提高讀性能
  • 對於寫操作是互斥的(不允許多個寫操作同時訪問同一資源)

關於讀寫鎖的模型

對於讀寫鎖,它允許多個讀者同時去讀取臨界資源,因此下圖中的讀線程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

在快速變化的技術中尋找不變,纔是一個技術人的核心競爭力。知行合一,理論結合實踐

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章