C++拾遺--多線程:臨界區解決子線程的互斥
前言
爲了解決子線程的互斥問題,windows系統提出了關鍵段或臨界區(CRITICAL_SECTION)的概念。它一共有四個共兩對操作:初始化、銷燬,進入、離開。它們定義在頭文件synchapi.h中。
1.初始化變量
VOID WINAPI InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
2.銷燬變量
VOID WINAPI DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
3.進入臨界區域
VOID WINAPI EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
函數說明:系統保證各個子線程互斥的進入臨界區域
4.離開臨界區域
VOID WINAPI LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
四個函數的使用都相當簡單,傳入CRITICAL_SECTION類型的變量地址即可。
正文
程序示例
下面我們使用關鍵段來解決子線程的互斥問題,程序代碼類似於原子操作解決線程衝突。每一個子線程都對同一個全局變量累加10。這次我們開啓50個子線程,查看最後的累加結果。
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <Windows.h>
#define Thread_NUM 50
CRITICAL_SECTION cs;
int g_count = 0;
void count(void *p)
{
Sleep(100); //do some work
//每個線程把g_count加1共10次
for (int i = 0; i < 10; i++)
{
//進入臨界區域
EnterCriticalSection(&cs);
g_count++;
//離開臨界區域
LeaveCriticalSection(&cs);
}
Sleep(100); //do some work
}
int main(void)
{
printf("******臨界區解決子線程衝突演示***by David***\n");
//初始化關鍵段變量cs
InitializeCriticalSection(&cs);
//共創建Thread_NUM個線程
HANDLE handles[Thread_NUM];
//共驗證10次
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < Thread_NUM; j++)
{
handles[j] = _beginthread(count, 0, NULL);
}
WaitForMultipleObjects(Thread_NUM, handles, 1, INFINITE);
printf("%d time g_count = %d\n", i, g_count);
//重置
g_count = 0;
}
//銷燬關鍵段變量cs
DeleteCriticalSection(&cs);
getchar();
return 0;
}
運行
從運行結果看,使用關鍵段確實可以解決子線程的衝突問題。在g_count++;的前後我們加上關鍵段的進入和離開,使這句代碼成爲了“臨界”區域。至此,g_count++;的操作就十分類似於原子操作。下面我們來詳細分析下關鍵段的使用原理。
關鍵段原理
關鍵段的定義
在minwinbase.h中
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
而在winnt.h中
typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
//
// The following three fields control entering and exiting the critical
// section for the resource
//
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread; // from the thread's ClientId->UniqueThread
HANDLE LockSemaphore;
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
關鍵段就是一結構體。具體原因後續分析……
本專欄目錄