Thread Synchronization in User Mode-Slim Read/Write Lock

The purpose of SRWLock is the same as that of key segments, but the difference is that SRWLock can distinguish which threads want to read shared resources and which to update shared resources. Threads that read shared resources can read the same shared resources at the same time because they do not destroy the data of the shared resources, but threads that update the shared resources must monopolize the shared resources. At this time, the read threads do not have permission to access the shared resources.

Update threads:
1. Define a SRWLOCk structure and initialize it with the Initialize SRWLock function:

VOID InitializeSRWLock(PSRWLOCK SRWLock);

2. After initialization, the writer thread can call AcquireSRWLockExclusive to try to gain exclusive rights of protected resources:

VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);

3. Unlock the resources after updating them

VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);

Read threads
Similar to read threads, except for the following two functions

VOID AcquireSRWLockShared(PSRWLOCK SRWLock);
VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);

SRWLOCk does not need to be deleted or destroyed, and the system will automatically perform cleaning.

#include "stdafx.h"
#include <windows.h>          
#include <process.h> 
#include <iostream>

using namespace std;

int g_x = 0;
SRWLOCK g_srwLock;

UINT WINAPI WriteThreadFunc1(PVOID pArguments)
{
    AcquireSRWLockExclusive(&g_srwLock);
    int n = 0;
    while (n < 3)
    {
        g_x += n;
        n++;
        cout << "WriteThreadFunc1.." << endl;
    }
    ReleaseSRWLockExclusive(&g_srwLock);
    _endthreadex(0);
    return 0;
}
UINT WINAPI WriteThreadFunc2(PVOID pArguments)
{
    AcquireSRWLockExclusive(&g_srwLock);
    int n = 0;
    while (n < 5)
    {
        g_x += n;
        n++;
        cout << "WriteThreadFunc2.." << endl;
    }
    ReleaseSRWLockExclusive(&g_srwLock);
    _endthreadex(0);
    return 0;
}
UINT WINAPI ReadThreadFunc1(PVOID pArguments)
{
    AcquireSRWLockShared(&g_srwLock);
    cout << "ReadThreadFunc1.." << endl;
    ReleaseSRWLockShared(&g_srwLock);
    _endthreadex(0);
    return 0;
}
UINT WINAPI ReadThreadFunc2(PVOID pArguments)
{
    AcquireSRWLockShared(&g_srwLock);
    cout << "ReadThreadFunc2.." << endl;
    ReleaseSRWLockShared(&g_srwLock);
    _endthreadex(0);
    return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE   handle1, handle2, handle3, handle4;
    unsigned  unThread1ID, unThread2ID;

    cout << "g_x initial value:  " << g_x << endl;
    InitializeSRWLock(&g_srwLock);
    handle1 = (HANDLE)_beginthreadex(NULL,
        0,
        &WriteThreadFunc1,
        NULL,
        0,
        &unThread1ID);
    handle2 = (HANDLE)_beginthreadex(NULL,
        0,
        &WriteThreadFunc2,
        NULL,
        0,
        &unThread2ID);
    handle3 = (HANDLE)_beginthreadex(NULL,
        0,
        &ReadThreadFunc1,
        NULL,
        0,
        &unThread1ID);
    handle4 = (HANDLE)_beginthreadex(NULL,
        0,
        &ReadThreadFunc2,
        NULL,
        0,
        &unThread2ID);
    WaitForSingleObject(handle1, INFINITE);
    WaitForSingleObject(handle2, INFINITE);
    WaitForSingleObject(handle3, INFINITE);
    WaitForSingleObject(handle4, INFINITE);
    cout << "g_x Final value:  " << g_x << endl;
    getchar();
    return 0;
}

Sometimes the output is as follows:

WriteThreadFunc1..
WriteThreadFunc1..
WriteThreadFunc1..
WriteThreadFunc2..
WriteThreadFunc2..
WriteThreadFunc2..
WriteThreadFunc2..
WriteThreadFunc2..
ReadThreadFunc1..ReadThreadFunc2..

The output of write threads is well understood, because they have exclusive resources, so write threads cannot run concurrently, but one by one.
Then someone asked me if my output wasn't like this? It could be the following three situations.

ReadThreadFunc2..ReadThreadFunc1..
ReadThreadFunc1..
ReadThreadFunc2..
ReadThreadFunc2..
ReadThreadFunc1..

In fact, it is well understood that read threads can access shared resources at the same time. So when the write thread is finished, the two read threads end the waiting state at the same time and become schedulable. The system may first execute ReadThreadFunc1, then execute ReadThreadFunc2, or vice versa. Thus, the following two output results appear:

ReadThreadFunc1..
ReadThreadFunc2..
ReadThreadFunc2..
ReadThreadFunc1..

It is also possible for ReadThreadFunc1 to execute to cout < < ReadThreadFunc1.] to this point, and then ReadThreadFunc1 is suspended and the system switches to ReadThreadFunc2 (ReadThreadFunc1 and ReadThreadFunc2 can be changed in sequence). This results in the following two output results:

ReadThreadFunc1..ReadThreadFunc2..
ReadThreadFunc2..ReadThreadFunc1..

Keywords: Windows

Added by parms on Fri, 07 Jun 2019 02:59:59 +0300