引言
多線程是一種很好的程序機制,使用線程可以充分的利用電腦資 源,進行並行的業務處理。不過好的東西總有它的不足。線程是好,不過濫用, 或管理不當就會造成線程混亂,內存漏洞,造成電腦速度變慢,反應遲鈍。
想法
於是有人提出能不能讓線程自己管理自己,把這復雜的工作 交給電腦來處理。筆者經過多年的實踐,終於用VC++實現了這一目的。
大家知道在VC++中我們可以用CreateThread創建一個線程,該函數返回這線程 的Handle,以後我們就可以用這個Handle來管理這個線程的。於是我們可以做一 個類名為ThreadManager,來管理這些Handle,並隨時監控這些線程的狀態。
總的思想就是這樣,不過為了方便使用,我們最好把這個類封裝成DLL的 形式,這樣以後我們在任何程序中都可以很方便的用該類來管理線程了(當然如果 你有興趣,也可以用COM模型來實現)。
實現
因為我們要把一切工 作全交給ThreadManager,所以線程的創建,監控,刪除都將在該類中實現,而我 們僅要做的就是把線程函數名和線程參數傳給ThreadManager類,於是我們定義該 類構造函數為:
ThreadManager(ThreadPrc threadpro,LPVOID pParam);
該類還要能啟動線程,於是我們又定義一個啟動函數:
RunThread();
另外我們有時還要能獲得線程的Handle,於 是又定義一個函數:
HANDLE GetThreadHandle();
而該類唯 一的成員參數就是Handle:
HANDLE m_Handle;
於是 ThreadManager定義如下:
typedef DWORD (WINAPI *ThreadPro) (LPVOID);
class CThreadManager : public CObject
{
DECLARE_DYNAMIC( CThreadManager )
public:
CThreadManager( ThreadPrc threadpro, LPVOID pParam);
~CThreadManager();
CBOOL RunThread();
HANDLE GetThreadHandle() const { return( m_Handle ); };
private:
HANDLE m_Handle;
};
顯然,我們僅有這一個類還不能完成我 們所需的工作,我們還要一個負責具體監控的ThreadTask類,ThreadTask類中有 一個監控線程ThreadTaskFunc( )負責監控並刪除線程。該類定義如下:
class CThreadTask : public CObject
{
DECLARE_DYNAMIC( CThreadTask )
public:
CThreadTask(); //構造函數
~CThreadTask();
CBOOL IsValid();
void AddHandle( CONST HANDLE cHandle ); //添加線程句柄到m_ObList中
void CloseThreadHandles(); //(關閉線程)
static CThreadTask& GetCThreadTask(); //用於在Managerthread類中 獲得ThreadTask類的指針
CObList m_ObList;//線程句柄組
HANDLE m_Handle;//線程句柄
BOOL m_bKeepGoing;//是否 已運行
};
IMPLEMENT_DYNAMIC( CThreadCareTaker, CObject )
其中IsValid()是用於檢驗ThreadTaskFunc()是否已動行了,其它意思 都很明顯。
流程圖
總的流程圖如下:
具體 實現
下面給出它的具體實現。
ThreadTask::ThreadTask()
{
m_bKeepGoing = TRUE;
//表示已運行
DWORD nThreadId = 0;
//創建管理線程
m_Handle = (HANDLE)::CreateThread(NULL,0,ThreadTaskpro,0,0,&nThreadId );
}
void ThreadTask::AddHandle( CONST HANDLE cHandle )
{
CHandle *pHandle = new CHandle;
pHandle- >m_ThreadHandle = cHandle;
m_ObList.AddTail( pHandle );
}
void ThreadTask::CloseThreadHandles()
{
if ( m_ObList.GetCount() )
{
POSITION pos1, pos2;
CHandle *pHandle = (CHandle *)NULL;
//(CHandle類 相當簡單,只有一個成員函數m_ThreadHandle)
DWORD dwExitCode = 0L;
for( pos1=m_ObList.GetHeadPosition(); (pos2=pos1)! =POSITION(NULL); )
{
//歷遍所有已有的線程 句柄
pHandle = DYNAMIC_DOWNCAST( CHandle, m_ObList.GetNext( pos1 ) );
//獲得第pos1個handle
VERIFY( ::GetExitCodeThread( pHandle->m_ThreadHandle, &dwExitCode ) );
//獲得線程pHandle的當前狀態
if ( dwExitCode != STILL_ACTIVE )
//如果已 完成
{
//釋放當前句柄
m_ObList.RemoveAt( pos2 );
VERIFY( ::CloseHandle( pHandle->m_ThreadHandle ) );
delete pHandle;
pHandle = (CHandle *)NULL;
}
}
}
}
ThreadTask::~ThreadTask()
{
}
ThreadTask & ThreadTask::GetThreadTask()
{
//返回靜態ThreadTask對象, 以便ThreadManager類調用
static ThreadTask Taker;
return(Taker);
}
BOOL ThreadTask::IsValid()
{
//是否已運行
BOOL bValid_Status = FALSE;
if ( (this != NULL) && AfxIsValidAddress( this, sizeof( ThreadTask ) ) )
bValid_Status = TRUE;
return( bValid_Status );
}
下面介紹線程ThreadTaskpro(); 該線程最主要的目的就是 調用ThreadTask的CloseThreadHandles()函數,實現如下:
DWORD WINAPI ThreadTaskpro( LPVOID pParam )
{
HANDLE hCurrentThread = GetCurrentThread();
//獲得該線程句柄
SetThreadPriority( hCurrentThread, THREAD_PRIORITY_LOWEST );
//設為最低
while ( ThreadTask::GetThreadTask().m_bKeepGoing )
{
Sleep(500);
//休息500mms
ThreadTask::GetThreadTask().CloseThreadHandles();
}
SetThreadPriority( hCurrentThread, THREAD_PRIORITY_NORMAL );
return( 0 );
}
ThreadTask類到這就介紹完了,下 面我們看看ThreadManager類的實現,其實它的工作已很小,就是啟動要管理的線 程(在構造函數中完成),並控制ThreadTask類。具體實現:
ThreadManager::ThreadManager(ThreadPro threadpro, LPVOID pParam)
{
DWORD nThreadId = 0;
_ASSERTE( ThreadTask::GetThreadTask().IsValid() );
//運行ThreadTask類
m_Handle = (HANDLE)::CreateThread(NULL,0,threadpro,(LPVOID) pParam,0,&nThreadId );
//創建要管理的線程,並返回句柄
if ( ThreadTask::GetThreadTask().m_bKeepGoing )
{
//如果ThreadTask運行了的話
ASSERT( m_Handle );
ThreadTask::GetThreadTask().AddHandle( m_Handle );
//把句柄加入ThreadTask類中,以便管理
}
}
ThreadManager::~ThreadManager()
{
}
BOOL ThreadManager::RunThread()
{
//運行線程
return( ::ResumeThread( m_Handle ) != 0xFFFFFFFF );
}
整在機制就 介紹完了。
使用方法
使用方法相當簡單,比如說,我要運行進程 MyThread1,並傳入參數m_pro,只要用以下代碼就可以了:
ThreadManager ThreadManager( &MyThread1, (LPVOID)m_pro );
ThreadManager.RunThread();
就可以了,用這種方法創 的線程,會自動由ThreadManager類管理,並在完成的工作時,自動釋放線程資源 。 我做了一個示例,大家可以試著運行一下。
本文配套源碼