1、臨界區對象
臨界區對象是定義在數據段中的一個CRITICAL_SECTION結構,Windows內部使用這個結構記錄一些同步信息,確保在同一段時間只有一個線程訪問數據段中的數據。
臨界區對象相關函數:
// 初始化臨界區對象資源
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
// 進入臨界區
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
// 離開臨界區
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
// 刪除臨界區對象資源
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
函數參數lpCriticalSection爲指向臨界區源的對象
2、臨界區對象實例
#include <iostream>
#include <Windows.h>
#include <process.h>
using namespace std;
int g_Cnt = 0; // 計數器
CRITICAL_SECTION g_cs; // 臨界區對象
BOOL bFlag = FALSE;// 判斷是否創建輔助線程
UINT _stdcall ThreadFunc(LPVOID lpParam);
int main()
{
UINT uId[2];
HANDLE h[2];
::InitializeCriticalSection(&g_cs); // 初始化臨界區資源
h[0] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId[0]);
h[1] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId[1]);
// 標誌創建了輔助線程
bFlag = TRUE;
// 主線程休息1000ms,讓出CPU的使用權,讓我們的輔助線程有運行的機會
Sleep(1000);
// 主線程運行
bFlag = FALSE;
::WaitForMultipleObjects(2, h, TRUE, INFINITE);
// 關閉句柄
CloseHandle(h[0]);
CloseHandle(h[1]);
::DeleteCriticalSection(&g_cs); // 清除臨界區資源
printf("g_Cnt = %d\n", g_Cnt);
system("pause");
return 0;
}
UINT _stdcall ThreadFunc(LPVOID lpParam)
{
if (bFlag)
{
::EnterCriticalSection(&g_cs);
for (int i =0;i< 10000;i++)
g_Cnt++;
::LeaveCriticalSection(&g_cs);
}
return 0;
}
臨界區對象能很好的保護共享數據,但是它不能夠用於進程之間資源的鎖定,因爲它不是內核對象,如果要在進程間維持線程的同步,可以使用事件內核對象。
3、互鎖函數
互鎖函數爲同步訪問多線程共享變量提供了一個簡單的機制。
如果變量在共享內存,不同進程的線程也可以使用此機制。
互鎖函數:
// 原子自加操作
InterlockedIncrement
// 原子自減操作
InterlockedDecrement
InterlockedExchangeAdd
InterlockedExchangePointer
4、實例
#include <iostream>
#include <Windows.h>
#include <process.h>
using namespace std;
int g_Cnt = 0; // 計數器
BOOL bFlag = FALSE;// 判斷是否創建輔助線程
UINT _stdcall ThreadFunc(LPVOID lpParam);
int main()
{
UINT uId[2];
HANDLE h[2];
h[0] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId[0]);
h[1] = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, &uId[1]);
// 標誌創建了輔助線程
bFlag = TRUE;
// 主線程休息1000ms,讓出CPU的使用權,讓我們的輔助線程有運行的機會
Sleep(1000);
// 主線程運行
bFlag = FALSE;
::WaitForMultipleObjects(2, h, TRUE, INFINITE);
// 關閉句柄
CloseHandle(h[0]);
CloseHandle(h[1]);
printf("g_Cnt = %d\n", g_Cnt);
system("pause");
return 0;
}
UINT _stdcall ThreadFunc(LPVOID lpParam)
{
if (bFlag)
{
for (int i = 0; i < 10000; i++)
// 原子自加操作,不會被中斷
InterlockedIncrement((long *)&g_Cnt);
}
return 0;
}
通過本節的學習,我們知道了如何控制關鍵的代碼段不被系統打斷,可以通過臨界區或者互鎖函數來實現關鍵代碼段不被系統打斷,可以保證數據得出正確的結果!