一、實現的技術如下:
1、以對象管理資源(例如:臨界區),即資源獲得即初始化(RAII)。
2、防止異常逃出解構函式,即必須捕捉解構函式產生的異常。
3、恰好足夠安全執行緒。
二、以對象管理資源:
1、不以對象管理資源分析:
以CCriticalSection類(見附錄源碼)為例分析如下:
(a)、該類可以實現臨界區管理功能,具體功能如下:
<1>、臨界區的初始化(Init())。
<2>、臨界區上鎖(Lock())。
<3>、臨界區解鎖(Unlock())。
<4>、臨界區的刪除(Term())。
(b)、該類的不足如下:
<1>、使用者可能在沒有初始化臨界區之前使用該臨界區。
例如:在沒有初始化前,對臨界區做上鎖、解鎖或者刪除臨界區,這都會使程式崩潰。
<2>、使用者可能在刪除臨界區後繼續使用該臨界區。
例如:在臨界區被刪除後,對臨界區做上鎖或者解鎖操作,這會導致程式崩潰。
<3>、使用者可能忘記刪除不再使用的臨界區。
例如:在臨界區不再使用後忘記刪除,這會產生記憶體流失。
<4>、使用者對臨界區上鎖後,可能忘記解鎖或者在解鎖前程式產生異常,這都可能導致該臨界區一直處於上鎖狀態,使其他使用者無法訪問被臨界區上鎖的資料,這也會產生無法刪除臨界區的記憶體流失。
2、以對象管理資源分析如下:
(a)、以CAutoCriticalSection類(見附錄源碼)為例分析如下:
該類的可以實現CCriticalSection的功能,同時還可以克服該類的不足。
該類的優點如下:
<1>、保證在使用該臨界區之前初始化改臨界區。
使用的技術為:資源獲得即初始化,即在該類的建構函式中初始化臨界區。
<2>、不會產生因使用者忘記刪除臨界區而產生記憶體流失。
實現方法為:在該函數的解構函式中刪除不再使用的臨界區。
<3>、在使用者刪除臨界區後,不會再使用臨界區。
實現方法為:在使用臨界區前先判斷該臨界區是否還存在,若存在可以繼續使用,若不存在就不再使用。
(b)、以CObjectLockT類(源碼見附錄)為例分析如下:
該類可以實現對CAutoCriticalSection類的管理,從而可以防止忘瞭解鎖的危險。
實現方法:在該類的建構函式裡對臨界區上鎖,在解構函式裡對臨界區解鎖。
原因:當離開該類對象的範圍或者產生異常時都會調用該類對象的解構函式,因此可以保證幹臨界區的解鎖。
三、解構函式和異常
1、解構函式不捕獲異常
在解構函式產生異常時,若此時捕獲就不再有捕獲的時機,那麼程式就會崩潰,用回也不會明白程式崩潰的原因。
2、在解構函式中捕獲異常
在必須在解構函式捕獲異常,當產生異常時捕獲異常,從而可以記下產生異常的原因,還可以讓程式正常終止。
3、 對外提供Term()函數的原因
既然在解構函式調用該函數,那麼對外提供該函數的原因是什嗎?
<1>、給使用者一個隨時刪除臨界區的權利,可以實現當臨界區不再使用時隨時刪除,節省記憶體的使用。
<2>、給使用者提供該函數的目的是給使用者一個自己處理錯誤的機會,若使用者認為該函數不會產生異常或者錯誤,那麼當在解構函式調用該函數產生錯誤或異常時使用者將無法再抱怨我們沒有給他處理錯誤的機會。
四、安全執行緒
通過給CObjectRootEx模板類傳遞不同的類(CMultiThreadModel和CSingleThreadModel)從而可以恰好足夠安全執行緒的控制。
1、 以CSingleThreadModel類為CObjectRootEx類的模板參數。
當為客戶的程式上鎖,即調用Lock()時,那麼最終調用的為CFakeCriticalSection類的Lock(),該類的Lock沒有做任何實現,僅僅是簡單返回。解鎖也一樣。
2、 以CMultiThreadModel類為CObjectRootEx類的模板參數。
當為客戶的程式上鎖,即調用Lock()時,那麼最終調用的為CCriticalSection類的Lock(),從而實現對臨界區的上鎖,可以防止多個線程的同時訪問。解鎖也一樣。
總結:
1、 若確信自己的程式不在多線程的環境下運行,那麼可以使自己的程式繼承CObjectRootEx類,並以CSingleThreadModel類為參數,這在現在看起來或許有點多餘。
2、 直到某一天自己的程式要運行在多線環境下,那麼只需要以CMultiThreadModel類替換CSingleThreadModel類,其他的什麼也不用變化,就可以實現線程同步訪問公用資料。
附錄:
/////////////////////////////////////////////////////
//Asynchronous code
////////////////////////////////////////////////////
#ifndef ASYN_H_
#define ASYN_H_
class CCriticalSection
{
public:
CCriticalSection()throw()
{
memset(&m_sec, 0, sizeof(CRITICAL_SECTION));
}
virtual ~CCriticalSection()
{
}
HRESULT Lock()throw()
{
EnterCriticalSection(&m_sec);
return S_OK;
}
HRESULT Unlock()throw()
{
LeaveCriticalSection(&m_sec);
return S_OK;
}
HRESULT Init()throw()
{
HRESULT hRes = E_FAIL;
try
{
InitializeCriticalSection(&m_sec);
hRes = S_OK;
}
catch ( ... )
{
hRes = E_OUTOFMEMORY;
}
return hRes;
}
HRESULT Term() throw()
{
DeleteCriticalSection(&m_sec);
return S_OK;
}
private:
CRITICAL_SECTION m_sec;
};
class CAutoCriticalSection : public CCriticalSection
{
public:
CAutoCriticalSection()
: m_bTermed(true)
{
HRESULT hr = CCriticalSection::Init();
if ( FAILED(hr) )
{
throw hr;
}
m_bTermed = false;
}
~CAutoCriticalSection()throw()
{
try
{
Term();
}
catch ( ... )
{
}
}
HRESULT Term()throw()
{
HRESULT hRes = S_OK;
if ( !m_bTermed )
{
m_bTermed = true;
hRes = CCriticalSection::Term();
}
return hRes;
}
private:
HRESULT Init();
private:
bool m_bTermed;
};
class CSafeDeleteCriticalSection : public CCriticalSection
{
public:
CSafeDeleteCriticalSection()
: m_bInitialized(false)
{
}
~CSafeDeleteCriticalSection()throw()
{
try
{
Term();//Derived class
}
catch ( ... )
{
//log
}
}
HRESULT Init()throw()
{
HRESULT hr = CCriticalSection::Init();
if ( SUCCEEDED(hr) )
{
m_bInitialized = true;
}
return hr;
}
HRESULT Term()throw()
{
HRESULT hRes = S_OK;
if ( m_bInitialized )
{
m_bInitialized = false;
hRes = CCriticalSection::Term();
}
return hRes;
}
HRESULT Lock()throw()
{
HRESULT hRes = S_OK;
if ( m_bInitialized )
{
hRes = CCriticalSection::Lock();
}
return hRes;
}
HRESULT Unlock()throw()
{
HRESULT hRes = S_OK;
if ( m_bInitialized )
{
hRes = CCriticalSection::Unlock();
}
return hRes;
}
private:
bool m_bInitialized;
};
class CFakeCriticalSection
{
public:
HRESULT Lock() throw() { return S_OK; }
HRESULT Unlock() throw() { return S_OK; }
HRESULT Init() throw() { return S_OK; }
HRESULT Term() throw() { return S_OK; }
};
class CMultiThreadModel
{
public:
typedef CAutoCriticalSection AutoDeleteCriticalSection;
};
class CSingleThreadModel
{
public:
typedef CFakeCriticalSection AutoDeleteCriticalSection;
};
//foward declaration
template < typename ThreadModel >
class CObjectLockT;
template < typename ThreadModel >
class CObjectRootEx
{
public:
typedef typename ThreadModel::AutoDeleteCriticalSection _AutoDelCritSec;
typedef CObjectLockT<ThreadModel> ObjectLock;
public:
void Lock()
{
m_critsec.Lock();
}
void Unlock()
{
m_critsec.Unlock();
}
private:
_AutoDelCritSec m_critsec;
};
template < typename ThreadModel >
class CObjectLockT
{
public:
CObjectLockT(CObjectRootEx<ThreadModel>* p)
: m_p(p)
, m_bUnlocked(false)
{
if ( m_p )
{
m_p->Lock();
}
}
~CObjectLockT()
{
try
{
Term();
}
catch ( ... )
{
//Prevent exception leak out from deconstruction
}
}
void Term()throw()
{
if ( !m_bUnlocked )
{
if ( m_p )
{
m_p->Unlock();
}
m_bUnlocked = true;
}
}
private:
CObjectLockT(const CObjectLockT&);
CObjectLockT& operator==(const CObjectLockT&);//
private:
CObjectRootEx<ThreadModel>* m_p;
bool m_bUnlocked;
};
#endif
//////////////////////////////////////////
///以下為測試代碼
#include <iostream>
#include <windows.h>
#include "asyn.h"
using namespace std;
///////////////////////////////////////////////////////////////////
///Test Code
//////////////////////////////////////////////////////////////////
class CTestClass
: public CObjectRootEx < CSingleThreadModel > //Test not asynchronous
//:public CObjectRootEx < CMultiThreadModel > //Test asynchronous
{
public:
void TestFunc();
};
void CTestClass::TestFunc()
{
ObjectLock clObjectLock(this); //Lock
cout << "CTestClass::TestFunc come in" << endl;
///Other code
///Your data does't be visited by multithread at the same time.
Sleep(3000);//Test Lock
cout << "Sleep over" << endl;
}
CTestClass clCTestClass;
DWORD ThreadProc(
LPVOID lpParameter
)
{
clCTestClass.TestFunc(); //Test Thread visit
return 0;
}
void main()
{
DWORD dwThreadID = 0;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&ThreadProc, NULL, 0, &dwThreadID);
clCTestClass.TestFunc();//Main Thread visit
Sleep(5000);
}
本文來自CSDN部落格,出處:http://blog.csdn.net/firststudy/archive/2009/03/01/3946294.aspx