Linux執行緒之讀寫鎖小結

Rice_rice發表於2024-06-01

讀寫鎖(rwlock)與互斥鎖(Mutex Lock)相比,有如下特點:

  • 更加細緻的區分了讀和寫,給共享資源分別上了“讀”鎖和“寫”鎖。
  • “寫”獨佔,“讀”共享,“寫”鎖優先順序更高
  • 如果共享資源在絕大多數情況下是“讀”操作,可以提高程式的併發效能。

常用的函式原型總結如下:

pthread_rwlock_t rwlock (= PTHREAD_RWLOCK_INITIALIZER); // 定義讀寫鎖的變數並初始化,一定要全域性變數,如果使用了下述初始化函式,括號內靜態初始化就可以取消
pthread_rwlock_init(&rwlock, NULL);                       // const pthread_rwlockattr_t *restrict attr,第二個引數預設為NULL
pthread_rwlock_rdlock(&rwlock);                           // 上讀鎖,並進行讀操作
pthread_rwlock_wrlock(&rwlock);                           // 上寫鎖,並進行寫操作,同一時間只有一把寫鎖,並與其他鎖互斥
pthread_rwlock_unlock(&rwlock);                           // 解鎖,讀和寫的解鎖函式都相同
pthread_rwlock_destroy(&rwlock);                          // 不用了就銷燬讀寫鎖

設計一個程式,程式中有3個執行緒,主執行緒A建立一個文字,每隔5s獲取一次系統時間並寫入到該文字中,另外兩個執行緒B和C分別從文字中讀取當前的時間和日期,子執行緒B輸出系統時間"hh:mm:ss",子執行緒c輸出系統日期"2024年05月31日”,要求使用讀寫鎖實現互斥。 提示:主執行緒A獲取寫操作的鎖,另外的執行緒分別獲取讀操作的鎖,程式如下:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>

FILE *timefp;            // 以檔案控制代碼為共享區
pthread_rwlock_t rwlock; // 定義讀寫鎖的變數,一定要全域性變數

// 需要用到的時間結構體,提前列出
//  struct tm {
//                 int tm_sec;    /* Seconds (0-60) */
//  int tm_min;   /* Minutes (0-59) */
//  int tm_hour;  /* Hours (0-23) */
//  int tm_mday;  /* Day of the month (1-31) */
//  int tm_mon;   /* Month (0-11) */
//  int tm_year;  /* Year - 1900 */
//  int tm_wday;  /* Day of the week (0-6, Sunday = 0) */
//  int tm_yday;  /* Day in the year (0-365, 1 Jan = 0) */
//  int tm_isdst; /* Daylight saving time */
//  }

void *funcB(void *arg) // B執行緒
{

    time_t tlocB = 0;
    while (1)
    {
        pthread_rwlock_rdlock(&rwlock); // 上鎖,進行讀操作
        timefp = fopen("/home/rice/0531/time.txt", "r+");
        fread(&tlocB, sizeof(time_t), 1, timefp);
        struct tm *tt = localtime(&tlocB);
        printf("I am thread B,the time is ===== %02d:%02d:%02d\n", tt->tm_hour, tt->tm_min, tt->tm_sec);
        pthread_rwlock_unlock(&rwlock); // 解鎖,釋放許可權
        fclose(timefp);
        sleep(2); // 每隔兩秒進行一次輸出
    }
}
void *funcC(void *arg)
{
    time_t tlocC = 0;
    while (1)
    {
        pthread_rwlock_rdlock(&rwlock); // 上鎖,進行讀操作
        timefp = fopen("/home/rice/0531/time.txt", "rb+");
        fread(&tlocC, sizeof(time_t), 1, timefp);
        struct tm *tt = localtime(&tlocC);
        printf("I am thread C,the date is ===== %d年:%02d月:%02d日\n", tt->tm_year + 1900, tt->tm_mon + 1, tt->tm_mday);
        pthread_rwlock_unlock(&rwlock); // 解鎖,釋放許可權
        fclose(timefp);
        sleep(2); // 每隔兩秒進行一次輸出
    }
}

int main()
{
    pthread_rwlock_init(&rwlock, NULL); // 初始化讀寫鎖

    pthread_t tidB, tidC;
    pthread_create(&tidB, NULL, funcB, NULL); // 建立執行緒
    pthread_create(&tidC, NULL, funcC, NULL);

    while (1) // 主執行緒每隔5秒獲取一次系統時間
    {
        pthread_rwlock_wrlock(&rwlock); // 上鎖,進行寫操作

        timefp = fopen("/home/rice/0531/time.txt", "wb+"); // 開啟檔案,不存在就建立
        time_t tloc = time(NULL);
        fwrite(&tloc, sizeof(time_t), 1, timefp); // 將time原始資料存入檔案
        fclose(timefp);
        pthread_rwlock_unlock(&rwlock); // 解鎖,釋放檔案許可權
        sleep(5);                       // 每隔5秒進行一次寫入操作
    }

    // 等待B和C執行緒結束
    pthread_join(tidB, NULL);
    pthread_join(tidC, NULL);
    // 銷燬讀寫鎖
    pthread_rwlock_destroy(&rwlock);

    return 0;
}

輸出結果如下:

I am thread B,the time is ===== 20:10:57
I am thread C,the date is ===== 2024年:06月:01日
I am thread B,the time is ===== 20:10:57
I am thread C,the date is ===== 2024年:06月:01日
I am thread C,the date is ===== 2024年:06月:01日
I am thread B,the time is ===== 20:10:57
I am thread B,the time is ===== 20:11:02
I am thread C,the date is ===== 2024年:06月:01日
I am thread B,the time is ===== 20:11:02
I am thread C,the date is ===== 2024年:06月:01日
...

相關文章