1. 程式人生 > >線程同步之讀寫鎖(鎖操作的補充)

線程同步之讀寫鎖(鎖操作的補充)

允許 資源 加鎖 函數 申請 tex bject def 讀取

輕量級的讀寫鎖(Slim Reader-Writer locks):讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。
這種鎖相對於自旋鎖而言,能提高並發性,因為在多處理器系統中,它允許同時有多個讀者來訪問共享資源,最大可能的讀者數為實際的邏輯CPU數。
寫者是排他性的,一個讀寫鎖同時只能有一個寫者或多個讀者(與CPU數相關),但不能同時既有讀者又有寫者。

讀寫鎖比起mutex具有更高的適用性,具有更高的並行性,可以有多個線程同時占用讀模式的讀寫鎖,但是只能有一個線程占用寫模式的讀寫鎖,讀寫鎖的三種狀態:
1.當讀寫鎖是寫加鎖狀態時,在這個鎖被解鎖之前,所有試圖對這個鎖加鎖的線程都會被阻塞
2.當讀寫鎖在讀加鎖狀態時,所有試圖以讀模式對它進行加鎖的線程都可以得到訪問權,但是以寫模式對它進行加鎖的線程將會被阻塞
3.當讀寫鎖在讀模式的鎖狀態時,如果有另外的線程試圖以寫模式加鎖,讀寫鎖通常會阻塞隨後的讀模式鎖的請求,這樣可以避免讀模式鎖長期占用,而等待的寫模式鎖請求則長期阻塞。

SRW代表-------Slim Reader-Writer

函數解析:

1.// 初始化讀寫鎖
VOID WINAPI InitializeSRWLock
(
  __out PSRWLOCK SRWLock
);
函數功能:初始化讀寫鎖


2.// 獨占式訪問
VOID WINAPI AcquireSRWLockExclusive

(
  __inout PSRWLOCK SRWLock
);
函數功能:寫入者線程申請寫資源。


3.// 獨占式釋放
VOID WINAPI ReleaseSRWLockExclusive

(
  __inout PSRWLOCK SRWLock
);
函數功能:寫入者線程寫資源完畢,釋放對資源的占用。


4.// 共享式訪問
VOID WINAPI AcquireSRWLockShared

(
  __inout PSRWLOCK SRWLock
);
函數功能:讀取者線程申請讀資源。

5.// 共享式釋放
VOID WINAPI ReleaseSRWLockShared

(
  __inout PSRWLOCK SRWLock
);
函數功能:讀取者線程結束讀取資源,釋放對資源的占用。

註意點:
1.訪問方式只能選擇其一,不可以同時使用。即一個線程僅能鎖定資源一次,不能多次鎖定資源。
2.讀寫鎖聲明後要初始化,但不用銷毀,系統會自動清理讀寫鎖。
3.讀取者和寫入者分別調用不同的申請函數和釋放函數。

區別:
1.AcquireSRWLockExclusive搶占式的,當線程上鎖後,其他線程無法進行訪問。直到 ReleaseSRWLockExclusive,釋放後。一般用於寫操作。
2.AcquireSRWLockShared 是共享式的,即使線程上鎖後,其他線程也可以進行再次訪問。一般用於讀操作。

源代碼:
// Semaphore.cpp : 定義控制臺應用程序的入口點。
//
#include "stdafx.h"
#include <Windows.h>
#include <process.h>

//線程數
#define  g_nThreadNum 3

//信號量
SRWLOCK g_srwLock;

//累加數
int g_nCount = 50;

unsigned _stdcall WriteThread(void * lParam)
{
    
    // 獨占式訪問
    AcquireSRWLockExclusive(&g_srwLock);
    
    g_nCount++;
    
    // 獨占式釋放
    ReleaseSRWLockExclusive(&g_srwLock);
    
    return 0;
}

unsigned _stdcall ReadThread(void *lParam)
{
    // 共享式訪問
    AcquireSRWLockShared(&g_srwLock);
    
    printf("g_nCount=%d\n", g_nCount);
    
    // 共享式釋放
    ReleaseSRWLockShared(&g_srwLock);

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    //// 初始化讀寫鎖
    InitializeSRWLock(&g_srwLock);
    //啟動線程
    HANDLE pThread[g_nThreadNum];
    
    pThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReadThread, NULL, 0, 0);
    
    pThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriteThread, NULL, 0, 0);

    pThread[2] = (HANDLE)_beginthreadex(NULL, 0, ReadThread, NULL, 0, 0);
    
    //等待線程結束
    WaitForMultipleObjects(g_nThreadNum, pThread, TRUE, INFINITE);

    printf("g_nCount:%d\n", g_nCount);

    //釋放資源
    for (int i = 0; i < g_nThreadNum; ++i)
    {
        CloseHandle(pThread[i]);
    }
    
    getchar();
    return 0;
}

線程同步之讀寫鎖(鎖操作的補充)