|
|
多執行緒同步之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;

 /**///////////////////////////////////////////////////////
// ·½·‥O»£o

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;
};

 /**///////////////////////////////////////////////////////
//·½·‥¶t£o

// 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;
};

// ¶OE«¾OμA±aA¿£¬E1OACritical 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列表:
Critical-section function Description DeleteCriticalSectionReleases all resources used by an unowned critical section object. EnterCriticalSectionWaits for ownership of the specified critical section object. InitializeCriticalSectionInitializes a critical section object. InitializeCriticalSectionAndSpinCountInitializes a critical section object and sets the spin count for the critical section. InitializeCriticalSectionExInitializes a critical section object with a spin count and optional flags. LeaveCriticalSectionReleases ownership of the specified critical section object. SetCriticalSectionSpinCountSets the spin count for the specified critical section. TryEnterCriticalSectionAttempts to enter a critical section without blocking.
[ 本帖最後由 f66666602 於 2007-8-14 04:49 編輯 ] |
|