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;
}