- 公開視頻 ->?鏈接點擊跳轉公開課程
- 博客首頁 ->?鏈接點擊跳轉博客主頁
目錄
競態條件
CriticalSection
Mutex
CriticalSection & Mutex
Semaphore
Event
競態條件
-
多線程環境下,當多個線程同時訪問或者修改同一個數據時,最終結果為線程執行的時許。
-
如果沒有同步機制,會發生競態條件,可能導致數據不準確,或者程序發生異常等。
#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;
}
CriticalSection
#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);// TODOg_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
-
互斥體(Mutex),用于防止多個線程同時訪問或修改共享資源。
-
同一時刻下只有一個線程可以擁有互斥體的所有權,如果一個線程擁有了互斥體的所有權,則其他請求該互斥體的線程將會被阻塞,直到互斥體權限釋放。
-
創建互斥體 - 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;
}
CriticalSection & Mutex
-
臨界區
-
共享資源的線程同步機制,臨界區在同一進程的線程之間提供了互斥訪問。
-
每個線程在訪問共享資源之前必須先能夠進入臨界區,在訪問結束后離開臨界區,完成線程同步。
-
-
互斥體
-
線程同步機制,用來限制多個線程同時訪問共享資源。
- 互斥體可以同步進程或者線程,且可以跨進程同步。
-
#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 \r\n", 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; }
- 如果線程在持有互斥體鎖的情況下意外終結,Windows會自動釋放其所有權,使得其他線程可以繼續正常執行。
-
#include <iostream> #include <Windows.h>HANDLE hMutex = NULL;DWORD WINAPI WorkThread1(LPVOID lp) {WaitForSingleObject(hMutex, INFINITE);printf("TID -> %d \r\n", GetCurrentThreadId());Sleep(5000);TerminateThread(GetCurrentThread(), -1);//todoreturn 0; }DWORD WINAPI WorkThread2(LPVOID lp) {printf("Wait For Thread1 Leave\r\n");WaitForSingleObject(hMutex, INFINITE);printf("TID -> %d \r\n", 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; }
Semaphore
-
信號量是一種同步對象,用于控制多個線程對共享資源的訪問。它是一個計數器,用來表示可用資源的數量。當信號量的值大于0,它表示有資源可用;當值為0,表示沒有可用資源。
-
等待:試圖減少信號量的值。如果信號量的值大于0,減1并繼續執行。如果信號量的值為0,則線程阻塞,直到信號量的值變為大于0。
-
釋放:增加信號量的值。如果有其他線程因等待這個信號量而阻塞,它們中的一個將被喚醒。
-
-
創建信號量
-
在 Windows 系統中,使用
CreateSemaphore
或CreateSemaphoreEx
函數創建信號量。
-
-
等待(Wait)和釋放(Release)信號量
-
等待信號量通常使用
WaitForSingleObject
或WaitForMultipleObjects
函數。 -
釋放信號量使用
ReleaseSemaphore
函數。
-
#include <iostream>
#include <Windows.h>#define MAX_COUNT_SEMAPHORE 3HANDLE 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);//closehandlereturn 0;
}
Event
-
在Windows編程中,事件是一種同步機制,用于在多個線程之間發送信號。事件對象可以是手動重置或自動重置。
-
手動重置事件(Manual Reset Event):當事件被設置(signaled)后,它將保持這個狀態直到顯式地被重置。這意味著多個等待該事件的線程都可以在事件被重置之前被喚醒。
-
自動重置事件(Auto Reset Event):當事件被一個等待的線程接收(signaled)后,系統會自動將事件狀態重置為非信號狀態(non-signaled)。這意味著每次只允許一個線程被喚醒。
-
-
創建事件
-
使用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;
}