除了臨界區對象進能夠被用於一個進程內的線程使用外,臨界區對象同於其他互斥體對象一樣,也可以提供同步機制.事件,互斥體和訊號量對象也能夠被用於單個進程實現資源互斥訪問,與此相比,為了實現同步互斥訪問共用資源,臨界區對象提供一種更加輕巧,快速和有效機制.象互斥體對象一樣,臨界區對象也可以被一個使用它來阻止同步訪問共用資源的線程所用於.例如:一個進程隨時可以使用一個臨界區對象來阻止其他線程修改一個局資料結構.
進程負責為一個臨界區分配記憶體.典型地,就是宣布一個CRITICAL_SECTION類型的變數.線程在使用它之前,臨界區對象必須使用InitializeCriticalSection函數進行初始化.線程使用EnterCriticalSection或TryEnterCriticalSection函數擷取臨界區所有權,並通過LeaveCriticalSection函數釋放臨界區所用權.如果當前臨界區對象被其他線程所擁有,EnterCriticalSection將無限等待為了臨界區所有權.相比之下,一個互斥體對象為了互斥,等待函數會有一個指定的時間段.TryEnterCriticalSection函數無阻塞正在調用的線程而進入臨界區.
一旦線程擁有臨界區,它必須額外的調用EnterCriticalSection或無阻塞他的執行的TryEnterCriticalSection函數.這樣以來,當等待一個已存在的臨界區的擁有權時,就不會出現死結自己.每當它進入臨界區時,就必須調用LeaveCriticalSection來釋放對臨界區的擁有權.
當臨界區被初始化之後,進程內的任一個線程都可以調用DeleteCriticalSection函數來釋放被分配了的系統資源.DeleteCriticalSection函數被調用之後,這個臨界區對象就不能夠再被擁有為了同步機制了.
一旦一個臨界區對象被特有化之後,通過調用EnterCriticalSection函數而關聯度其它的線程將等待為了它的擁有權.沒有等到擁有權的線程釋
放去繼續運行.
SECTICAL_SECTION結構:
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;
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
typedef PRTL_CRITICAL_SECTION PCRITICAL_SECTION;
typedef PRTL_CRITICAL_SECTION LPCRITICAL_SECTION;
操作臨界區的相關函數
(1) InitializeCriticalSection
初始化一個臨界區對象,而臨界區對象(資料成員)由系統自動維護.
VOID InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection //pointer to critical section object
);
(2) DeleteCriticalSection
釋放一個沒有被佔有的臨界區對象的所有資源.
VOID DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection //pointer to critical section object
);
(3) EnterCriticalSection
用來等待臨界區對象的所有權,當調用線程賦予所有權,本函數返回,如果沒能等待到,那麼導致線程暫停.
VOID EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection //pointer to critical section object
);
(4) LeaveCriticalSection
釋放指定臨界區對象所有權
void LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection //pointer to critical section object
);
例子:
CRITICAL_SECTION g_cs; //臨界區對象
void main()
{
HANDLE thread1 = CreateThread(NULL, 0, Fun1Proc, NULL, 0, NULL);
HANDLE thread2 = CreateThread(NULL, 0, Fun2Proc, NULL, 0, NULL);
CloseHandle(thread1);
CloseHandle(thread2);
//初始化一個臨界區對象
InitializeCriticalSection(&g_cs);
Sleep(4000);
//釋放一個沒有被佔有的臨界區對象的所有資源
DeleteCriticalSection(&g_cs);
}
DWORD WINAPI Fun1Proc(LPVOID lpParam)
{
while(TRUE)
{
EnterCriticalSection(&g_cs);
if (ticket>0)
{
cout<<"thread1 sells: "<<ticket--<<endl;
Sleep(1);
}
else
break;
LeaveCriticalSection(&g_cs);
}
return 0;
}
DWORD WINAPI Fun1Proc(LPVOID lpParam)
{
while(TRUE)
{
EnterCriticalSection(&g_cs);
if (ticket>0)
{
cout<<"thread2 sells: "<<ticket--<<endl;
Sleep(1);
}
else
break;
LeaveCriticalSection(&g_cs);
}
return 0;
}
//以下是我自己編寫實現臨界區的類:
//標頭檔 CriticalSection.h
#pragma once
class CCriticalSection
{
private:
CRITICAL_SECTION m_CS;
public:
CCriticalSection()
{
::InitializeCriticalSection(&m_CS);
}
~CCriticalSection()
{
::DeleteCriticalSection(&m_CS);
}
operator LPCRITICAL_SECTION()
{
return &m_CS;
}
void Lock()
{
::EnterCriticalSection(&m_CS);
}
void UnLock()
{
::LeaveCriticalSection(&m_CS);
}
};