Win32API SRWLock

Windows VistaからSRWLock(Slim Reader/Writer Lock)が導入された。


目的はクリティカルセクションと同じだが、共有ロックと排他ロックを別々に適用することで、パフォーマンスが向上を図ることができるところがメリットになる。




SRWLockに関する主な関数には、以下の5つがある。

InitializeSRWLock
AcquireSRWLockExclusive
ReleaseSRWLockExclusive
AcquireSRWLockShared
ReleaseSRWLockShared

SRWLockは自動的に解放されるため、クリティカルセクションのDeleteCriticalSectionのようにSRWLockを解放するための関数は存在しない。





InitializeSRWLock関数は、SRWLOCKオブジェクトを初期化する。この関数で初期化されたSRWLOCKオブジェクトを用いて、オブジェクトに対して共有ロックや排他ロックを行う。


InitializeSRWLockのプロトタイプ

VOID WINAPI InitializeSRWLock(
  _Out_  PSRWLOCK SRWLock //SRWLOCK構造体へのポインタ
);




AcquireSRWLockExclusive関数は、排他ロックを獲得する。
AcquireSRWLockExclusive関数のプロトタイプ

VOID WINAPI AcquireSRWLockExclusive(
  _Inout_  PSRWLOCK SRWLock
);




ReleaseSRWLockExclusive関数は、排他ロックを解放する。
ReleaseSRWLockExclusiveのプロトタイプ

VOID WINAPI ReleaseSRWLockExclusive(
  _Inout_  PSRWLOCK SRWLock
);





AcquireSRWLockShared関数は、共有ロックを獲得する。
AcquireSRWLockSharedのプロトタイプ

VOID WINAPI AcquireSRWLockShared(
  _Inout_  PSRWLOCK SRWLock
);




ReleaseSRWLockShared関数は、共有ロックを解放する。
ReleaseSRWLockSharedのプロトタイプ

VOID WINAPI ReleaseSRWLockShared(
  _Inout_  PSRWLOCK SRWLock
);




SRWLockで排他ロックを行うサンプルプログラム
複数のスレッドを用いて、1つの整数オブジェクトをインクリメントする。

#include <windows.h>
#include <stdio.h>

static PTP_WORK g_pWorkItem;
static SRWLOCK g_SRWLock;
static CRITICAL_SECTION g_Crit;
static __int64 g_nCount = 0;


void NTAPI WorkCallback(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
    for (int i = 0; i < 10000; i++) {
        AcquireSRWLockExclusive(&g_SRWLock);
        printf("g_nCount = %d\n", g_nCount++);
        ReleaseSRWLockExclusive(&g_SRWLock);
    }
}

int main()
{
    InitializeSRWLock(&g_SRWLock);
    g_pWorkItem = ::CreateThreadpoolWork(WorkCallback, NULL, NULL);

    for (int i = 0; i < 10; i++) {
        SubmitThreadpoolWork(g_pWorkItem);
    }

    WaitForThreadpoolWorkCallbacks(g_pWorkItem, FALSE);

    CloseThreadpoolWork(g_pWorkItem);

    return 0;
}




次に、共有ロックと排他ロックを用いたサンプルプログラムを示す。

1つの整数オブジェクトをWriterThread関数とReaderThread関数で共有している。

WriterThread関数では、排他ロックを用いて整数オブジェクトをインクリメントし、

ReaderThread関数では共有ロックを用いて整数オブジェクトの値を読み取って表示している。

双方のスレッドで整数オブジェクトの値がMAXCOUNTに達したら関数を終了させる。

#include <Windows.h>
#include <stdio.h>

static PTP_WORK g_pWorkItemReader;
static PTP_WORK g_pWorkItemWriter;
static SRWLOCK g_SRWLock;
static __int64 g_nCount = 0;
static const __int64 MAXCOUNT = 1000000;

//共有ロックを用いて g_nCount の値を読み取り、コンソールに表示する
void NTAPI ReaderThread(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
    while (1) {
        __try {
            AcquireSRWLockShared(&g_SRWLock);
            
            printf("g_nCount = %ld\n", g_nCount);
            if (g_nCount >= MAXCOUNT)
            {
                break;
            }

        } __finally {
            ReleaseSRWLockShared(&g_SRWLock);
        }
    }
}

//排他ロックを用いて g_nCount の値をインクリメントする
void NTAPI WriterThread(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
    while (1) {
        __try {
            AcquireSRWLockExclusive(&g_SRWLock);
            
            if (g_nCount >= MAXCOUNT) {
                break;
            }
            g_nCount++;

        } __finally {
            ReleaseSRWLockExclusive(&g_SRWLock);
        }
    }
}

int main()
{
    //SRQLOCK構造体オブジェクトを初期化
    ::InitializeSRWLock(&g_SRWLock);
    
    //WriterThread関数, ReaderThread関数のスレッドプールを生成
    g_pWorkItemWriter = ::CreateThreadpoolWork(WriterThread, NULL, NULL);
    g_pWorkItemReader = ::CreateThreadpoolWork(ReaderThread, NULL, NULL);
    
   
    //WriterThread関数とReaderThread関数によるスレッドを共に100個生成する
    for (int i = 0; i < 100; i++) {
        SubmitThreadpoolWork(g_pWorkItemWriter);
        SubmitThreadpoolWork(g_pWorkItemReader);
    }
    
    //双方のスレッドの完了を待機する
    WaitForThreadpoolWorkCallbacks(g_pWorkItemWriter, FALSE);
    WaitForThreadpoolWorkCallbacks(g_pWorkItemReader, FALSE);

    printf("Complete! - g_nCount = %d\n", g_nCount);

    //スレッドプールオブジェクトを解放
    CloseThreadpoolWork(g_pWorkItemWriter);
    CloseThreadpoolWork(g_pWorkItemReader);

    return 0;
}






参考

InitializeSRWLock http://msdn.microsoft.com/ja-jp/library/windows/desktop/ms683483(v=vs.85).aspx
AcquireSRWLockExclusive http://msdn.microsoft.com/en-us/library/windows/desktop/ms681930(v=vs.85).aspx
ReleaseSRWLockExclusive http://msdn.microsoft.com/en-us/library/windows/desktop/ms685076(v=vs.85).aspx
AcquireSRWLockShared http://msdn.microsoft.com/en-us/library/windows/desktop/ms681934(v=vs.85).aspx
ReleaseSRWLockShared http://msdn.microsoft.com/en-us/library/windows/desktop/ms685080(v=vs.85).aspx