不管是硬件臨界資源,仍是軟件臨界資源,多個線程必須互斥地對它進行訪問。每一個線程中訪問臨界資源的那段代碼稱爲臨界區(Critical Section)。
每一個線程中訪問臨界資源的那段程序稱爲臨界區(Critical Section)(臨界資源是一次僅容許一個線程使用的共享資源)。每次只准許一個線程進入臨界區,進入後不容許其餘線程進入。不管是硬件臨界資源,仍是軟件臨界資源,多個線程必須互斥地對它進行訪問。
windows的Critical Section提供了4個API,分別是:windows
void WINAPI InitializeCriticalSection( _Out_ LPCRITICAL_SECTION lpCriticalSection );
void WINAPI DeleteCriticalSection( _Inout_ LPCRITICAL_SECTION lpCriticalSection );
void WINAPI EnterCriticalSection( _Inout_ LPCRITICAL_SECTION lpCriticalSection );
void WINAPI LeaveCriticalSection( _Inout_ LPCRITICAL_SECTION lpCriticalSection );
臨界區是一種輕量級機制,在某一時間內只容許一個線程執行某個給定代碼段。一般在修改全局數據(如集合類)時會使用臨界區。事件、多用戶終端執行程序和信號量也用於多線程同步,但臨界區與它們不一樣,它並不老是執行向內核模式的控制轉換,這一轉換成本昂貴。稍後將會看到,要得到一個未佔用臨界區,事實上只須要對內存作出不多的修改,其速度很是快。只有在嘗試得到已佔用臨界區時,它纔會跳至內核模式。這一輕量級特性的缺點在於臨界區只能用於對同一進程內的線程進行同步。多線程
經過InitializeCriticalSection完成初始化,經過DeleteCriticalSection結束控制;經過EnterCriticalSection開啓控制,在這個階段系統只執行下面的代碼;其餘進程等待他的結束,最後經過LeaveCriticalSection來結束這種控制。函數
咱們經過如下兩段代碼予以分析:線程
#include "stdafx.h" #include <Windows.h> #include <process.h> int num = 0; CRITICAL_SECTION cs; unsigned WINAPI ThreadFun1(void *arg) { int cnt = *(int*)arg; EnterCriticalSection(&cs); for (int i = 0; i < cnt; i++) { num += 1; printf("Inc "); Sleep(10); } LeaveCriticalSection(&cs); return 0; } unsigned WINAPI ThreadFun2(void *arg) { int cnt = *(int*)arg; EnterCriticalSection(&cs); for (int i = 0; i < cnt; i++) { num -= 1; printf("Dec "); Sleep(10); } LeaveCriticalSection(&cs); return 0; } int main() { int param = 50; HANDLE h[2]; InitializeCriticalSection(&cs); h[0]= (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, ¶m, 0, NULL); if (h[0] == 0) { printf("Can not create a thread 1.\n"); return 0; } h[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, ¶m, 0, NULL); if (h[1] == 0) { printf("Can not create a thread 2.\n"); return 0; } WaitForMultipleObjects(2, h, true, INFINITE); DeleteCriticalSection(&cs); printf("The num is %d, and end of main.\n", num); return 0; }
咱們在每一個進程的計算過程均使用了臨界資源進行了控制,所以在這兩個進程的執行過程當中,其計算循環都是獨立完成的,其運行結果以下:code
Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Dec Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc Inc The num is 0, and end of main. 請按任意鍵繼續. . .
從結果上咱們能夠明細看出,兩個函數的循環計算過程當中,沒有其餘進程參與進來是獨立運行完成的;進程
若是咱們將控制只獨立在計算自己而不是控制到循環全過程,代碼以下:事件
#include "stdafx.h" #include <Windows.h> #include <process.h> int num = 0; CRITICAL_SECTION cs; unsigned WINAPI ThreadFun1(void *arg) { int cnt = *(int*)arg; for (int i = 0; i < cnt; i++) { EnterCriticalSection(&cs); num += 1; printf("Inc "); LeaveCriticalSection(&cs); Sleep(10); } return 0; } unsigned WINAPI ThreadFun2(void *arg) { int cnt = *(int*)arg; for (int i = 0; i < cnt; i++) { EnterCriticalSection(&cs); num -= 1; printf("Dec "); LeaveCriticalSection(&cs); Sleep(10); } return 0; } int main() { int param = 50; HANDLE h[2]; InitializeCriticalSection(&cs); h[0]= (HANDLE)_beginthreadex(NULL, 0, ThreadFun1, ¶m, 0, NULL); if (h[0] == 0) { printf("Can not create a thread 1.\n"); return 0; } h[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun2, ¶m, 0, NULL); if (h[1] == 0) { printf("Can not create a thread 2.\n"); return 0; } WaitForMultipleObjects(2, h, true, INFINITE); DeleteCriticalSection(&cs); printf("The num is %d, and end of main.\n", num); return 0; }
將控制移到循環體內,這樣只能保證計算自己是獨立的,而循環是無控制的,其運行結果就變得混亂了:ip
Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec Inc Dec The num is 0, and end of main.