私の連絡先情報
郵便メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
目次
マルチスレッド環境では、複数のスレッドが同時に同じデータにアクセスまたは変更する場合、最終的な結果はスレッドの実行時間になります。
同期メカニズムがない場合、競合状態が発生し、不正確なデータやプログラムの例外が発生する可能性があります。
- #include <iostream>
- #include <windows.h>
-
- DWORD g_Num = 0;
-
- DWORD WINAPI WorkThread(LPVOID lp)
- {
- for (size_t i = 0; i < 10000000; i++)
- {
- //g_Num++;
- __asm LOCK INC [g_Num]
- }
- return 0;
- }
-
- int main()
- {
- HANDLE hThread[2] = { 0 };
- hThread[0] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
- hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
- WaitForMultipleObjects(2, hThread, TRUE, -1);
- std::cout << g_Num << std::endl;
-
- return 0;
- }
- #include <iostream>
- #include <windows.h>
-
- DWORD g_Num = 0;
- CRITICAL_SECTION cs = { 0 };
-
- DWORD WINAPI WorkThread(LPVOID lp)
- {
- for (size_t i = 0; i < 1000000; i++)
- {
- // 进入临界区
- EnterCriticalSection(&cs);
-
- // TODO
- g_Num++;
-
- // 退出临界区
- LeaveCriticalSection(&cs);
- }
- return 0;
- }
-
- int main()
- {
-
- HANDLE hThread[2] = { 0 };
- // 初始临界区
- InitializeCriticalSection(&cs);
-
- hThread[0] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
- hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
-
- WaitForMultipleObjects(2, hThread, TRUE, -1);
-
- std::cout << g_Num << std::endl;
-
- // 清理临界区
- DeleteCriticalSection(&cs);
-
- return 0;
- }
Mutex (ミューテックス) は、複数のスレッドが同時に共有リソースにアクセスしたり変更したりするのを防ぐために使用されます。
ミューテックスを同時に所有できるのは 1 つのスレッドだけです。1 つのスレッドがミューテックスの所有権を取得した場合、ミューテックスの権限が解放されるまで、ミューテックスを要求している他のスレッドはブロックされます。
ミューテックスを作成する - CreateMutex
ミューテックスのリクエスト - WaitForSingleObject
ミューテックスを解放する - ReleaseMutex
- #include <iostream>
- #include <windows.h>
-
- HANDLE hMutex = 0;
- DWORD g_Num = 0;
-
- DWORD WINAPI WorkThread(LPVOID lp)
- {
- for (size_t i = 0; i < 100000; i++)
- {
- WaitForSingleObject(hMutex, INFINITE);
- g_Num++;
- ReleaseMutex(hMutex);
- }
-
- return 0;
- }
-
- int main()
- {
- hMutex = CreateMutex(NULL, FALSE, NULL);
-
- HANDLE hThread1 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
- HANDLE hThread2 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
-
- WaitForSingleObject(hThread1, INFINITE);
- WaitForSingleObject(hThread2, INFINITE);
-
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- CloseHandle(hMutex);
-
- std::cout << g_Num << std::endl;
-
- return 0;
- }
クリティカルセクション
共有リソースのスレッド同期メカニズム、クリティカル セクションは、同じプロセスのスレッド間で相互排他的アクセスを提供します。
各スレッドは、共有リソースにアクセスする前にクリティカル セクションに入り、アクセスが完了してスレッドの同期を完了した後にクリティカル セクションから出ることができる必要があります。
ミューテックス
スレッド同期メカニズムは、複数のスレッドが共有リソースに同時にアクセスすることを制限するために使用されます。
- #include <iostream>
- #include <Windows.h>
-
- int main()
- {
- HANDLE hMutex = CreateMutex(NULL, FALSE, L"0xCC_Mutex");
- if (hMutex == NULL) return 0;
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- {
- MessageBox(NULL, L"禁止多开", L"错误", MB_OKCANCEL);
- return 0;
- }
- std::cout << "Game Start..." << std::endl;
- system("pause");
- CloseHandle(hMutex);
- return 0;
- }
パフォーマンス
クリティカル セクションは、同じプロセスのスレッド内のミューテックスより高速です。
関数
ミューテックスはプロセス間で同期できますが、クリティカル セクションは同じプロセス内のスレッド間でのみ同期できます。
所有
ミューテックスには厳密な所有権要件があり、ミューテックス権限を持つスレッドのみがミューテックスを解放できます。
- #include <iostream>
- #include <Windows.h>
-
- CRITICAL_SECTION CriticalSection = { 0 };
-
- DWORD WINAPI WorkThread(LPVOID lp)
- {
- EnterCriticalSection(&CriticalSection);
-
- printf("TID -> %d rn", GetCurrentThreadId());
- Sleep(5000);
-
- LeaveCriticalSection(&CriticalSection);
-
- return 0;
- }
-
- int main()
- {
- InitializeCriticalSection(&CriticalSection);
-
- HANDLE hThread1 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
- Sleep(1000);
- TerminateThread(hThread1, 1);
-
- HANDLE hThread2 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
- WaitForSingleObject(hThread2, INFINITE);
-
- DeleteCriticalSection(&CriticalSection);
-
- return 0;
- }
- #include <iostream>
- #include <Windows.h>
-
- HANDLE hMutex = NULL;
-
- DWORD WINAPI WorkThread1(LPVOID lp)
- {
- WaitForSingleObject(hMutex, INFINITE);
- printf("TID -> %d rn", GetCurrentThreadId());
- Sleep(5000);
- TerminateThread(GetCurrentThread(), -1);
-
- //todo
- return 0;
- }
-
- DWORD WINAPI WorkThread2(LPVOID lp)
- {
- printf("Wait For Thread1 Leavern");
- WaitForSingleObject(hMutex, INFINITE);
- printf("TID -> %d rn", GetCurrentThreadId());
- ReleaseMutex(hMutex);
- return 0;
- }
-
-
- int main()
- {
- hMutex = CreateMutex(NULL, FALSE, NULL);
-
- HANDLE hThread1 = CreateThread(NULL, 0, WorkThread1, NULL, 0, NULL);
- Sleep(1000);
-
- HANDLE hThread2 = CreateThread(NULL, 0, WorkThread2, NULL, 0, NULL);
- WaitForSingleObject(hThread2, INFINITE);
-
- CloseHandle(hMutex);
- CloseHandle(hThread1);
- CloseHandle(hThread2);
-
- return 0;
- }
セマフォは、複数のスレッドによる共有リソースへのアクセスを制御するために使用される同期オブジェクトです。利用可能なリソースの量を表すカウンターです。セマフォの値が 0 より大きい場合は、リソースが使用可能であることを示し、値が 0 の場合は、使用可能なリソースがないことを示します。
待って : セマフォの値を減らそうとします。セマフォ値が 0 より大きい場合は、値を 1 減らして実行を続行します。セマフォの値が 0 の場合、スレッドはセマフォの値が 0 より大きくなるまでブロックします。
解放された : セマフォの値を増やします。このセマフォを待機している他のスレッドがブロックされている場合、そのうちの 1 つが起動されます。
セマフォの作成
Windows システムでは、次を使用します。 CreateSemaphore
またはCreateSemaphoreEx
関数はセマフォを作成します。
待機 (Wait) および解放 (Release) セマフォ
セマフォの待機は通常、次を使用して行われます。 WaitForSingleObject
またはWaitForMultipleObjects
関数。
セマフォの使用を解放する ReleaseSemaphore
関数。
- #include <iostream>
- #include <Windows.h>
-
- #define MAX_COUNT_SEMAPHORE 3
-
-
- HANDLE g_SemapHore = NULL;
- HANDLE g_hThreadArr[10] = { 0 };
-
- DWORD WINAPI WorkThread(LPVOID lp)
- {
- WaitForSingleObject(g_SemapHore, INFINITE);
-
- for (size_t i = 0; i < 10; i++)
- {
- std::cout << "COUNT -> " << (int)lp << std::endl;
- Sleep(500);
- }
-
- ReleaseSemaphore(g_SemapHore, 1, NULL);
-
- return 0;
- }
-
- int main()
- {
- g_SemapHore = CreateSemaphore(
- NULL, //安全属性
- MAX_COUNT_SEMAPHORE, //初始计数
- MAX_COUNT_SEMAPHORE, //最大计数
- NULL //信号名称
- );
-
- if (g_SemapHore == NULL)
- {
- std::cout << GetLastError() << std::endl;
- return 1;
- }
-
- for (size_t i = 0; i < 10; i++)
- {
- g_hThreadArr[i] = CreateThread(
- NULL,
- 0,
- WorkThread,
- (LPVOID)i,
- 0,
- NULL
- );
- }
-
- WaitForMultipleObjects(10, g_hThreadArr, TRUE, INFINITE);
-
- //closehandle
-
- return 0;
- }
Windows プログラミングでは、イベントは複数のスレッド間で信号を送信するために使用される同期メカニズムです。イベント オブジェクトは次のとおりです。手動リセットまたは自動リセット。
手動リセット イベント: イベントが設定される (通知される) と、明示的にリセットされるまでこの状態が維持されます。これは、イベントがリセットされる前に、イベントを待機している複数のスレッドが起動される可能性があることを意味します。
自動リセット イベント: 待機中のスレッドによってイベントが受信される (シグナルされる) と、システムはイベントの状態を自動的に非シグナル (非シグナル) にリセットします。これは、一度に 1 つのスレッドのみを起動できることを意味します。
イベントの作成
Windows API関数の使用CreateEvent
イベントオブジェクトを作成できる
lpEventAttributes
: セキュリティ属性へのポインタ (に設定されている場合)NULL
の場合、デフォルトのセキュリティが使用されます。
bManualReset
: もしTRUE
の場合は手動リセット イベントが作成され、それ以外の場合は自動リセット イベントが作成されます。
bInitialState
: もしTRUE
の場合、初期状態は信号状態です。FALSE
、それは非信号状態です。
lpName
: イベントの名前。
イベントを設定するには (イベント状態を信号状態に設定するには)、次を使用します。SetEvent
関数
イベントをリセットするには (イベント状態を非シグナル状態に設定するには)、次を使用します。ResetEvent
関数
イベントオブジェクトがシグナル状態になるまで待機します。WaitForSingleObject
関数
- #include <iostream>
- #include <Windows.h>
-
- DWORD WINAPI WorkThread(LPVOID lp)
- {
- HANDLE hEvent = *(HANDLE*)lp;
- std::cout << "Thread - " << GetCurrentThreadId() << " Waiting For Event" << std::endl;
- WaitForSingleObject(hEvent, INFINITE);
- std::cout << "Thread - " << GetCurrentThreadId() << " actived" << std::endl;
- return 0;
- }
-
- int main()
- {
- HANDLE hThreads[3] = { 0 };
- HANDLE hEvent = NULL;
-
- hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (hEvent == NULL) return 0;
-
- for (size_t i = 0; i < 3; i++)
- {
- hThreads[i] = CreateThread(NULL, 0, WorkThread, &hEvent, 0, NULL);
- }
-
- Sleep(2000);
- SetEvent(hEvent);
-
- WaitForMultipleObjects(3, hThreads, TRUE, INFINITE);
-
- CloseHandle(hEvent);
-
- return 0;
- }