在並行處理過程中多線程對同一對象進行操作,而且操作各自獨立,但又需要依賴對象
本身的狀態,如已打開或已登錄等等。這時需要給狀態進行引用計數,以保證操作的有效和
並發性。
為了便於描述, 以<遠程文件系統>中的客戶端連接對象類(TRFConnObj)中部分代碼做為
示例:
// 對象狀態
enum TObjState
{osInactive = 0, // 未打開
osClosing = 1, // 正在關閉
osOpening = 2, // 正在打開
osOpened = 3}; // 已經打開
// 引用計數加 1
bool TRFConnObj::IncRefCount()
{
// 初始化
bool result = false;
// 操作
Lock();
if (FState == osOpened)
{
FRefCount++;
result = true;
}
Unlock();
// 返回結果
return result;
}
// 引用計數減 1
void TRFConnObj::DecRefCount()
{
Lock();
if (FRefCount > 0)
FRefCount--;
Unlock();
}
// 打開
long TRFConnObj::Open()
{
// 初始化
long result = crStateInvalid;
bool boolNext = false;
// 更改狀態
Lock();
if (FState == osInactive)
{
FState = osOpening;
boolNext = true;
FRefCount= 0;
}
else if (FState == osOpened)
result = crSuccess;
Unlock();
// 判斷是否繼續
if (boolNext)
{
// 執行打開
boolNext = false;
result = DoOpen();
// 更改狀態
Lock();
if (FState != osOpening)
boolNext = true;
else if (result == crSuccess)
FState = osOpened;
else
FState = osInactive;
Unlock();
// 判斷是否需要關閉
if (boolNext)
{
// 執行關閉
if (result == crSuccess)
{
DoClose(true);
result = crFailure;
}
// 更改狀態(不需要加鎖)
FState = osInactive;
}
}
// 返回結果
return result;
}
// 關閉
void TRFConnObj::Close(bool ANeedWait)
{
// 初始化
bool boolNext = false;
bool boolWait = false;
// 更改狀態
Lock();
if (FState == osOpened)
{
FState = osClosing;
boolNext = true;
}
else if (FState == osOpening)
{
FState = osClosing;
boolWait = true;
}
else if (FState == osClosing)
boolWait = ANeedWait;
Unlock();
// 判斷是否等待
if (boolWait)
{
// 等待 Close 結束
while (FState == osClosing)
Sleep(15);
}
else if (boolNext)
{
// 執行關閉
DoClose(true);
// 更改狀態(不需要加鎖)
FState = osInactive;
}
}
// 並行操作的方法
long TRFConnObj::(...)
{
// 初始化
long result = crStateInvalid;
// 引用計數加 1
if (IncRefCount())
{
// 操作
// ??? ... ...
// 引用計數減 1
DecRefCount();
}
// 返回結果
return result;
}
可以把 Open 和 Close 方法理解為打開和關閉並行處理之門,只有 Open 之後才有效。
當調用 Close 方法時,若還有其它線程正在操作相關方法,則會等待操作完成後才能關閉,
若已調用 Close 方法且狀態為 osClosing 且其它線程開始操作相關方法時,則會直接返回
狀態無效,並拒之門外。
對象狀態和引用計數配合使用會提高事件處理的並發性,且不會在邊界狀態時導致異常
發生,同時還可以保證系統的並發性能。在服務器程序的開發中會常用到引用計數和狀態,
若完全理解 Open 和 Close 中狀態處理,則有助於靈活運用到並發性高的軟件開發中。
<遠程文件系統>提供完整源碼,下載地址如下:
遠程文件系統服務器源碼[http://download.csdn.net/detail/kyee/5109478]
遠程文件系統客戶端源碼[http://download.csdn.net/detail/kyee/5109484]
服務器和客戶端相關接口[http://download.csdn.net/detail/kyee/5109491]
客戶端連接對象類(TRFConnObj)部分代碼如下:
// 返回值及錯誤碼
enum TRFCResult
{crSuccess = 1, // 成功
crFailure = 0, // 失敗
crUnknown = -1, // 未知錯誤
crNotExist = -2, // 不存在(如: AConnObj)
crNotStart = -3, // 服務器未啟動
crNotConnect = -4, // 連接未打開
crNonsupport = -5, // 不支持
crVersion = -6, // 版本太低
crPassword = -7, // 密碼錯誤
crIsExisted = -8, // 已存在
crIsIllegal = -9, // 不合法
crAttrInvalid = -10, // 屬性無效
crStateInvalid = -11, // 狀態無效
crHandleInvalid = -12, // 句柄無效
crAccessIllegal = -13}; // 存取非法
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* TRFConnObj - 客戶端連接對象類 */
class TRFConnObj
{
public:
TRFConnObj(TRFConnEvent* AEventObj = NULL, const char* AHost = NULL,
long APort = 0, const char* APassword = NULL);
virtual ~TRFConnObj();
// 屬性
void* Data() const { return FData; }
TRCConnection* ConnObj() const { return FConnObj; }
TRFConnEvent* EventObj() const { return FEventObj; }
Longword CallTimeout() const { return FCallTimeout; }
TObjState State() const { return FState; }
KYString RFVersion() const { return FRFInfo.Version; }
TDateTime RFStartTime() const { return FRFInfo.StartTime; }
TDateTime RFDateTime();
// 設置屬性
void SetData(void* AData) { FData = AData; }
void SetCallTimeout(Longword ATimeout);
// 打開/關閉連接
long Open();
void Close(bool ANeedWait = false);
// 讀取/設置文件屬性
long GetFileAttr(const char* AFileName, long* Attrib);
long SetFileAttr(const char* AFileName, long Attrib);
// 文件存在/刪除/移動文件或目錄
long FileExisted(const char* AFileName);
long DeleteFile(const char* AFileName);
long MoveFile(const char* AOldName, const char* ANewName);
// 目錄存在/創建/刪除
long DirExisted(const char* APathName);
long CreateDir(const char* APathName, bool AForced = false);
long RemoveDir(const char* APathName, bool AForced = false);
// 磁盤操作相關函數
long DriveType(const char* ADrive, long* AType);
long DiskSpace(const char* APath, __int64* ATotalSpace,
__int64* AFreeSpace);
protected:
// 狀態鎖
void Lock() const { FLock->Enter(); }
void Unlock() const { FLock->Leave(); }
// 對象次數增減
long IncObjTimes() { return InterlockedIncrement(&FObjTimes); }
long DecObjTimes() { return InterlockedDecrement(&FObjTimes); }
// 引用計數增減
bool IncRefCount_Valid();
bool IncRefCount();
void DecRefCount();
// 讀取 RF 的信息
void GetRFInfo();
void GetRFDateTime();
// 存取 RF 屬性方法
long GetRFInt(long Attrib, long& AValue);
long GetRFStr(long Attrib, KYString& AValue);
long SetRFInt(long Attrib, long AValue);
long SetRFStr(long Attrib, const char* AValue, long ALen);
private:
// 執行初始化/釋放
void DoInit();
void DoFreeing() { FEventObj->DoFreeing(this); }
// 執行打開/關閉
long DoOpen();
void DoClose(bool ANeedClose);
// 執行斷開連接
void DoDisconnect();
void CallOnDisconnect();
// 執行 RC 事件的回調方法
void DoRecvData(const void* AData, long ASize);
private:
void* FData; // 自定義數據
TKYCritSect* FLock; // 狀態鎖
TRCConnection* FConnObj; // RC 連接對象
TRFConnEvent* FEventObj; // 事件對象
TObjState FState; // 狀態
long FObjTimes; // 對象次數
long FRefCount; // 引用計數
Longword FCallTimeout; // 調用超時時長(毫秒)
TRFInfo FRFInfo; // 存儲服務器信息
Longword FLastTick; // 讀取最後一次 RFDateTime 的 tick 值
TDateTime FDeltaTime; // 存儲服務器的當前時間差值
TRFCOnDisconnect FOnDisconnect; // OnDisconnect 回調事件函數
private:
// RC 連接的回調函數
static void __stdcall _DoRCCallback(long AConnID, long AEvent,
long ACmdID, long AReturn);
static void __stdcall _DoRCRecvData(long AConnID, long ASize, const void* AData);
};