//
// 引用計數在長時間軸程過程中的使用
// cheungmine
//
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
// It should be used if the worker class will use CRT functions
static HANDLE CrtCreateThread(LPSECURITY_ATTRIBUTES lpsa,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE pfnThreadProc,
LPVOID pvParam,
DWORD dwCreationFlags,
LPDWORD pdwThreadId)
{
// _beginthreadex calls CreateThread which will set the last error value before it returns
return (HANDLE) _beginthreadex(lpsa,
dwStackSize,
(unsigned int (__stdcall *)(void *)) pfnThreadProc,
pvParam,
dwCreationFlags,
(unsigned int *) pdwThreadId);
}
class CUserdata
{
public:
CUserdata():m_data(100)
{
printf("CUserdata()/n");
}
~CUserdata()
{
printf("~CUserdata()/n");
}
int m_data;
};
template< typename _Type > class ThreadParamT
{
volatile ULONG m_cRef;
// 私人的析構方法保證由引用計數自動管理對象的生存期
~ThreadParamT()
{
printf("~ThreadParamT()::m_cRef=%d/n", m_cRef);
}
public:
ULONG AddRef()
{
return (ULONG) InterlockedIncrement((volatile LONG*)&m_cRef);
}
ULONG Release()
{
if (InterlockedDecrement((volatile LONG*)&m_cRef)==0)
{
delete this;
return 0;
}
return m_cRef;
}
ThreadParamT():
m_cRef(1)
{
printf("ThreadParamT()::m_cRef=%d/n", m_cRef);
}
_Type t;
};
// 線程過程: 長時間執行的 線程過程
// AddRef() 和 Release()必須線上程中成對調用
static DWORD WINAPI LongTimeThreadProc( LPVOID lpParam )
{
ThreadParamT<CUserdata> *pthrParam = (ThreadParamT<CUserdata> *) lpParam;
// 入口處立即增加引用計數
pthrParam->AddRef();
// 類比執行一個長時間的任務
printf("LongTimeThreadProc::Do a long time job....../n");
SleepEx(10000, 0);
// 返回時必須減少引用計數
pthrParam->Release();
return 0;
}
int main()
{
// 建立線程過程參數, 這個參數傳遞給線程之後, 生存期就由引用計數控制
ThreadParamT<CUserdata> * thrParam = new ThreadParamT<CUserdata>();
DWORD dwThrId;
HANDLE hThread = CrtCreateThread(0, 0, LongTimeThreadProc, (LPVOID)thrParam, 0, &dwThrId);
// 下面的代碼假設我們來不急等待線程執行結束
// 此時, thrParam 的生存期有引用計數管理是適當的
DWORD dwRet = WaitForSingleObject(hThread, 5000);
assert(dwRet==WAIT_TIMEOUT);
CloseHandle(hThread);
// 此時仍可訪問線程資料, 注意是否使用關鍵區保護
printf("此時仍可訪問線程資料: %d/n", thrParam->t.m_data);
// 此時釋放引用計數, 如果線程未結束, 則資料並未釋放
thrParam->Release();
SleepEx(6000, 0);
printf("thrParam 已經不可用, 此時不可訪問線程資料: %d/n", thrParam->t.m_data);
return 0;
}