1 はじめに
クリティカル セクションは、実行前に共有リソースへの排他的アクセスを必要とする小さなコードです。このアプローチにより、複数行のコードで「アトミックな方法」でリソースを操作できます。
使用する機能:
指定されたクリティカル セクション オブジェクトの所有権を待機します。呼び出し元のスレッドに所有権が付与されると、関数は戻ります。
void EnterCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
指定されたクリティカル セクション オブジェクトの所有権を解放します。
void LeaveCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
クリティカル セクション オブジェクトを初期化します。EnterCriticalSection を呼び出す前に、初期化関数を呼び出す必要があります。
void InitializeCriticalSection(
[out] LPCRITICAL_SECTION lpCriticalSection
);
リソースを解放します。
void DeleteCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
2. 例
この例では、2 つのスレッドが作成されます。グローバル変数 g_sum を累積します。
// Interlocked.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <windows.h>
DWORD WINAPI add0(LPVOID);
DWORD WINAPI add1(LPVOID);
int g_count = 10;
long g_sum = 0;
CRITICAL_SECTION g_cs;
int main()
{
HANDLE aThread[2];
DWORD ThreadID;
InitializeCriticalSection(&g_cs);
aThread[0] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)add0,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if (aThread[0] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
aThread[1] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)add1,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if (aThread[1] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
WaitForMultipleObjects(2, aThread, TRUE, INFINITE);
// Close thread and mutex handles
for (int i = 0; i < 2; i++)
CloseHandle(aThread[i]);
DeleteCriticalSection(&g_cs);
return 0;
}
DWORD WINAPI add0(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
EnterCriticalSection(&g_cs);
g_sum = 0;
for (int i = 0; i < g_count; i++)
{
g_sum += i;
}
printf("Thread %d g_sum = %d\n",
GetCurrentThreadId(), g_sum);
LeaveCriticalSection(&g_cs);
return g_sum;
}
DWORD WINAPI add1(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
EnterCriticalSection(&g_cs);
g_sum = 0;
for (int i = 0; i < g_count; i++)
{
g_sum += i;
}
printf("Thread %d g_sum = %d\n",
GetCurrentThreadId(), g_sum);
LeaveCriticalSection(&g_cs);
return g_sum;
}
まず、CRITICAL_SECTION g_cs データ構造を定義する必要があります。次に、共通リソース (g_sum) にアクセスする必要があるコードをEnterCriticalSection と LeaveCriticalSection の間に配置します。着信 g_cs がアドレスであることに注意してください。
Interlocked 機能を使用して同期の問題を解決できない場合は、クリティカル セクションを試してください。その最大の利点は、非常に使いやすいことと、Interlocked 機能を内部で使用していることですが、最大の欠点は、複数のプロセス間でスレッドを同期するために使用できないことです。
3. ミューテックス カーネル オブジェクト
4. ミューテックス オブジェクトとキー セグメントの類似点と相違点
ミューテックス オブジェクトの動作特性はクリティカル コード セグメントと同じですが、ミューテックス オブジェクトはカーネル オブジェクトに属し、クリティカル コード セグメントはユーザー モード オブジェクトに属します。これは、ミューテックスがコードのクリティカル セクションよりも遅く実行されることを意味します。ただし、これは、異なるプロセスの複数のスレッドが 1 つのミューテックス オブジェクトにアクセスできることも意味します。また、スレッドがリソースへのアクセスを待機している間にタイムアウト値を設定できることも意味します。
特性 | ミューテックス オブジェクト | キーセグメント |
走行速度 | 遅い | 素早い |
プロセスの境界を越えて使用できますか | はい | いいえ |
声明 | ハンドル hmtx; | CRITICAL_SECTION cs; |
初期化 | hmtx = CreateMutex(NULL,FALSE,NULL); | InitializeCriticalSection(&es); |
クリアする | CloseHandle(hmtx); | DeleteCriticalSection(&cs); |
無限に待つ | WaitForSingleObject(hmtx ,INFINITE); | EnterCriticalSection(&cs); |
0 待機中 | WaitForSingleObject(hmtx , 0); | EnterCriticalSection(&cs); |
任意待機 | WaitForSingleObject(hmtx,dwMilliseconds); | できない |
解放された | リリースミューテックス(hmtx); | LeaveCriticalSection(&cs); |
他のカーネルオブジェクトを待つことは可能ですか? | はい (WaitForMultipleObjects または同様の関数を使用) | いいえ |