多線程同步之Critical Sections(功能與Mutex相同,保證某一時刻只有一個線程能夠訪問共享資源,但是不是內核對象,所以訪問速度要比Mutex快,但是增沒有等待超時的功能,所以有可能會導致死鎖,使用時可以根據實際的情況選擇其一)
一 Critical Sections
1) 因為Critical Sections不是內核對象,所以只能用來統一進程內線程間的同步,不能用來多個不同進程間的線程的同步。
2) 如果在Critical Sections中間突然程序crash或是exit而沒有調用LeaveCriticalSection,則結果是改線程所對應的內核不能被釋放,該線程成為死線程。
3) 要比其他的內核對象的速度要快。
二 使用CriticalSections的簡單實例,Stack在push的時候可以分為3個步驟,看下面的代碼,但是如果在第2步后此線程中斷切換到其他的線程,其他的線程push后再返回執行時,此線程繼續執行,這樣有可能剛才其他線程push就會被覆蓋了,在stack里找不到了。(下面的代碼在debug下使用了CriticalSection,release下可能有問題)
#include <windows.h>
#include <process.h>
#include <stdio.h>

/**//////////////////////////////////////////////
//stack:
struct Node


{
struct Node *next;
int data;
};
struct Stack


{
struct Node *head;
#ifdef _DEBUG
CRITICAL_SECTION critical_sec;
#endif

Stack()

{
head = NULL;
#ifdef _DEBUG
InitializeCriticalSection(&critical_sec);
#endif
}
~Stack()

{
if(head != NULL)

{
if(NULL == head->next)

{
delete head;
head = NULL;
}
else

{
Node *p = head;
Node *q = head->next;

while(q != NULL)

{
delete p;
p = q;
q = q->next;
};
delete p;
p = NULL;
}
}
#ifdef _DEBUG
DeleteCriticalSection(&critical_sec);
#endif
}
void Push (int num)

{
//enter critical section, add a new node and then
#ifdef _DEBUG
EnterCriticalSection (&critical_sec);
#endif
Node * node = new Node();
node->next = head;
node->data = num;
head = node;
printf("Stack:%d\n",num);
//leave critical section
#ifdef _DEBUG
LeaveCriticalSection (&critical_sec);
#endif
}
int Pop ()

{
#ifdef _DEBUG
EnterCriticalSection (&critical_sec);
#endif
int result = 0;
if(head!= NULL)

{
result = head->data;
if(head->next != NULL)

{
Node *temp = head->next;
delete head;
head = temp;
}
else
head = NULL;
}
#ifdef _DEBUG
LeaveCriticalSection (&critical_sec);
#endif
return result;
}
};


/**///////////////////////////////////////////////////////
//test:
unsigned __stdcall Thread1(void * pVoid)


{
Stack *stack = ((Stack*)pVoid);
for(int i = 200; i<220;++i)

{
stack->Push(i);
}
return 1;
}
unsigned __stdcall Thread2(void *pVoid)


{
Stack *stack = ((Stack*)pVoid);
for(int i = 0; i<20; ++i)

{
stack->Push(i);
}
return 1;
}
int main()


{
Stack stack;
stack.Push(1000);
stack.Push(1000);

HANDLE hth1;
unsigned uiThread1ID;

hth1 = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
Thread1,
(void*)&stack, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread1ID );

if ( hth1 == 0 )
printf("Failed to create thread 1\n");

DWORD dwExitCode;

GetExitCodeThread( hth1, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "initial thread 1 exit code = %u\n", dwExitCode );



HANDLE hth2;
unsigned uiThread2ID;

hth2 = (HANDLE)_beginthreadex( NULL, // security
0, // stack size
Thread2,
(void*)&stack, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread2ID );

if ( hth2 == 0 )
printf("Failed to create thread 2\n");

GetExitCodeThread( hth2, &dwExitCode ); // should be STILL_ACTIVE = 0x00000103 = 259
printf( "initial thread 2 exit code = %u\n", dwExitCode );

ResumeThread( hth1 );
ResumeThread( hth2 );

WaitForSingleObject( hth1, INFINITE );
WaitForSingleObject( hth2, INFINITE );

GetExitCodeThread( hth1, &dwExitCode );
printf( "thread 1 exited with code %u\n", dwExitCode );

GetExitCodeThread( hth2, &dwExitCode );
printf( "thread 2 exited with code %u\n", dwExitCode );

CloseHandle( hth1 );
CloseHandle( hth2 );

printf("Primary thread terminating.\n");
}
三 對Critical Section的封裝:
//////////////////////////////////////////////////////
// 方法一: Lock中的CritSect成員變量必須是引用類型。
class CritSect


{
public:
friend class Lock;

CritSect()
{ InitializeCriticalSection(&_critSection); }

~CritSect()
{ DeleteCriticalSection(&_critSection); }
private:

void Acquire()
{EnterCriticalSection(&_critSection);}

void Release()
{LeaveCriticalSection(&_critSection);}

CRITICAL_SECTION _critSection;
};

class Lock


{
public:

Lock(CritSect& critSect):_critSect(critSect)
{ _critSect.Acquire(); }

~Lock()
{_critSect.Release();}
private:
CritSect& _critSect;
};
//////////////////////////////////////////////////////
//方法二:
// MT-exclusive lock

class CLock
{
public:

CLock()
{ InitializeCriticalSection (&m_criticalSection); }

void Lock ()
{ EnterCriticalSection (&m_criticalSection); }

void Unlock ()
{ LeaveCriticalSection (&m_criticalSection); }

virtual ~CLock()
{ DeleteCriticalSection (&m_criticalSection); }
private:
CRITICAL_SECTION m_criticalSection;
};


// Scoped MT-exclusive lock

class CScopedLocker
{
public:

CScopedLocker (CLock * t) : m_lock (t)
{ m_lock->Lock(); }

~CScopedLocker()
{ m_lock->Unlock(); }
private:
CLock * m_lock;
};
對上面的2中封裝的調用都比較簡單,都是只有2行代碼。
CritSect sect;
Lock lock(sect);
或
CLock t;
CSCopedLocker st(&t);
下面的對封裝的測試代碼,保證了對g_n全局變量在線程1操作結束后線程2才可以操作。(下面的代碼因為對全局變量同步,所以需要申明含有CRITICAL_SECTION的類為全局)
#include<windows.h>
#include<iostream>
using namespace std;


/**///////////////////////////////////////////////////////
// ·½·¨Ò»£º

class CritSect


{
public:
friend class Lock;

CritSect()
{ InitializeCriticalSection(&_critSection); }

~CritSect()
{ DeleteCriticalSection(&_critSection); }
private:

void Acquire()
{EnterCriticalSection(&_critSection);}

void Release()
{LeaveCriticalSection(&_critSection);}

CRITICAL_SECTION _critSection;
};

class Lock


{
public:

Lock(CritSect& critSect):_critSect(critSect)
{ _critSect.Acquire(); }

~Lock()
{_critSect.Release();}
private:
CritSect& _critSect;
};


/**///////////////////////////////////////////////////////
//·½·¨¶þ£º

// MT-exclusive lock

class CLock
{
public:

CLock()
{ InitializeCriticalSection (&m_criticalSection); }

void Lock ()
{ EnterCriticalSection (&m_criticalSection); }

void Unlock ()
{ LeaveCriticalSection (&m_criticalSection); }

virtual ~CLock()
{ DeleteCriticalSection (&m_criticalSection); }
private:
CRITICAL_SECTION m_criticalSection;
};


// Scoped MT-exclusive lock

class CScopedLocker
{
public:

CScopedLocker (CLock * t) : m_lock (t)
{ m_lock->Lock(); }

~CScopedLocker()
{ m_lock->Unlock(); }
private:
CLock * m_lock;
};

// ¶ÔÈ«¾ÖµÄ±äÁ¿£¬Ê¹ÓÃCritical Section
// Declare the global variable
static int g_n;
CritSect sect;
//CLock t;




/**/////////Thread One Function///////////////////
UINT ThreadOne(LPVOID lParam)


{
Lock lock(sect);
//CScopedLocker st(&t);
for(int i=0;i<100;i++)

{
g_n++;
cout << "Thread 1: " << g_n << "\n";
}
// return the thread
return 0;
}



/**/////////Thread Two Function///////////////////
UINT ThreadTwo(LPVOID lParam)


{


Lock lock(sect);
//CScopedLocker st(&t);

for(int i=300;i<400;i++)

{
g_n++;
cout << "Thread 2: "<< g_n << "\n";
}

// return the thread
return 0;
}


int main()


{

// Create the array of Handle
HANDLE hThrd[2];
//Thread ID's
DWORD IDThread1, IDThread2;


// Create thredas use CreateThread function with NULL Security
hThrd[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) ThreadOne,(LPVOID)NULL,0,&IDThread1);
hThrd[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) ThreadTwo,(LPVOID)NULL,0,&IDThread2);

// Wait for the main thread
WaitForMultipleObjects(2,hThrd,TRUE,INFINITE);
return 0;
}
四 API列表: