有不少的時候,我們都需要一個這樣的線程類來管理我們的線程。
現在我做一個最簡單的一個線程管理類。
我們的這個線程當然會開始一個線程。並且會讓用戶能寫一個線程處理函數加到我的這個類裏來。
所以這個會要從外部讀入一個處理函數的一個函數指針給我。
自己寫這個處理函數的時候會需要入口參數,這裏我設計使用一個void*類型來傳入。
這樣就比較的好。因爲所有使用這個變量可以把所有的類型都傳過來。使用指針全都可以傳成這個類型。
在這個時間我們可以解決了這個類要如何與外部的接口了。
那我們如何來管理這個線程的開啓,工作,退出呢?
使用到二個Event對象。
一個Event是管理這個線程是不是要工作,還有一個是不是把這個線程給關閉。
總結一下。這個類可能需要的成員變量會有:
PFUN m_pFn;//函數指針
void* m_pParam;//參數
HANDLE m_eventArr[2];//二個等待的事件
成員函數
CThreadManager(PFUN _pFun,void* _pParam);//構造函數
void Start();//開啓線程
void Work();//開始工作
void Close();//它將會把這個線程關閉
~CThreadManager();//
static DWORD WorkProcess(void* _param);//線程管理類中的線程函數
這樣就得到一個這樣的類了
// ThreadManager.h: interface for the CThreadManager class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_THREADMANAGER_H__C22364D8_F0DE_4391_B4E3_8DA3A1B720DB__INCLUDED_)
#define AFX_THREADMANAGER_H__C22364D8_F0DE_4391_B4E3_8DA3A1B720DB__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "wtypes.h"
#include <vector>
#include "Winbase.h"
using namespace std;
typedef long (*PFUN)(void* _param);
typedef vector<HANDLE> HandleArr;
typedef vector<int> intArr;
const int THREADMANAGER_USERLESS=(unsigned int )-1;
//線程管理類
class CThreadManager
{
public:
CThreadManager(PFUN _pFun,void* _pParam);
CThreadManager();
virtual ~CThreadManager();
//接口函數
void BeginProcess();//開啓線程
void NotifyProcess();//開始工作
void ExitProcess();//它將會把這個線程關閉
virtual int RewriteFun();//可以重載的函數
protected:
int m_nWaitTime;
int m_nThreadNo;
PFUN m_pFn;
void* m_pParam;
HANDLE m_eventArr[2];
HANDLE m_eventExit;
HANDLE m_eventWoked;
static DWORD WINAPI WorkProcess(void* _param);
static DWORD WINAPI WorkProcessEx(void* _param);
void InitParam();
};
#endif // !defined(AFX_THREADMANAGER_H__C22364D8_F0DE_4391_B4E3_8DA3A1B720DB__INCLUDED_)
// ThreadManager.cpp: implementation of the CThreadManager class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ThreadManager.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CThreadManager::CThreadManager(PFUN _pFun,void* _pParam)
{
m_pFn=_pFun;
m_pParam=_pParam;
m_nWaitTime=THREADMANAGER_USERLESS;
InitParam();
}
CThreadManager::CThreadManager()
{
m_pFn=NULL;
m_pParam=NULL;
InitParam();
}
int CThreadManager::RewriteFun()
{
return 0;
}
CThreadManager::~CThreadManager()
{
ExitProcess();
CloseHandle(m_eventArr[0]);
CloseHandle(m_eventArr[1]);
CloseHandle(m_eventExit);
CloseHandle(m_eventWoked);
}
void CThreadManager::InitParam()
{
m_nWaitTime=THREADMANAGER_USERLESS;
m_eventArr[0]=::CreateEvent(NULL,FALSE,FALSE,NULL);
m_eventArr[1]=::CreateEvent(NULL,FALSE,FALSE,NULL);
m_eventExit=::CreateEvent(NULL,TRUE,FALSE,NULL);
m_eventWoked=::CreateEvent(NULL,FALSE,FALSE,NULL);
}
void CThreadManager::BeginProcess()
{
DWORD dwID;
HANDLE hTemp;
if (m_pFn==NULL)
{
hTemp=::CreateThread(NULL,0,WorkProcessEx,this,NULL,&dwID);
}else
{
hTemp=::CreateThread(NULL,0,WorkProcess,this,NULL,&dwID);
}
::CloseHandle(hTemp);
}
void CThreadManager::NotifyProcess()
{
::SetEvent(m_eventArr[1]);
::WaitForSingleObject(m_eventWoked,INFINITE);
}
void CThreadManager::ExitProcess()
{
::SetEvent(m_eventArr[0]);
::WaitForSingleObject(m_eventExit,INFINITE);
}
DWORD CThreadManager::WorkProcess(void* _param)
{
CThreadManager *pObj=(CThreadManager*)_param;
DWORD dwRet=-1;
while (1)
{
dwRet=::WaitForMultipleObjects(
2,
pObj->m_eventArr,
FALSE,
INFINITE);
if (dwRet==WAIT_TIMEOUT)
continue;
dwRet-=WAIT_OBJECT_0;
if (dwRet==0)
goto exit;
else
{
::SetEvent(pObj->m_eventWoked);
if ((*pObj->m_pFn)(pObj->m_pParam)==-1)
{
goto exit;
}
}
}
exit:
::SetEvent(pObj->m_eventExit);
return 0;
}
DWORD CThreadManager::WorkProcessEx(void* _param)
{
CThreadManager *pObj=(CThreadManager*)_param;
DWORD dwRet=-1;
while (1)
{
dwRet=::WaitForMultipleObjects(
2,
pObj->m_eventArr,
FALSE,
INFINITE);
if (dwRet==WAIT_TIMEOUT)
continue;
dwRet-=WAIT_OBJECT_0;
if (dwRet==0)
goto exit1;
else
{
::SetEvent(pObj->m_eventWoked);
if (pObj->RewriteFun()==-1)
{
goto exit1;
}
}
}
exit1:
::SetEvent(pObj->m_eventExit);
return 0;
}
這是一個很簡單的單線程的管理類。如果想把這個類改成一個線程池也比較的簡單了。
就只要把這個工作的事件修改爲一個自動Reset的模式,而這個退出的事件就要設置爲
不使用自動Reset的。這個的區別在才如果使用自動的,那這個事件只能使用一次。
還要在start函數裏增加線程的個數。這樣就初步出來了一個線程池對象。
但是這樣做出來的話有一些問題。
就是退出我們的線程的時候要如何做。
這裏可以看出來。我們只是把一個事件設置了一下。這樣線程類裏的函數遇到了這個事件就
會退出來,這個會有一個問題。如果當我們的線程還沒有處理完成,外部調用了類的這個設置
事件函數。當然也不會等待就會退出了。外部的一些對象開始析構了。可能當前線程處理函數
會要使用到外部傳來的一個對象的this指針。可以想象得出來,這樣就會把程序給搞得崩掉。
解決的辦法有一個。在這個退出函數裏要等待一個事件,就是這個線程處理的完成之時會要把這個
事件給Set一下。這樣就可以保證我們的調用退出函數之後。我們的線程一定可以退出來。
這樣也會代來新的問題。就是,當外部傳入的函數,中可能能調用到這個線程管理類的退出函數。
這樣就會有一個死鎖的問題。
如: A類裏,我寫了一個處理函數,把一個線程類加爲成員變量,在這個處理函數中,我使用的參數是
A類的this指針,處理函數中有一句這樣的話:pObj->m_ThreadManager->Close();
這時,如果有這個需要的話,我們可以定義一個處理函數的返回數值來決定我們的這個線程類是不是要把
這一些線程退出了。也就是說,不要使用已上的方式,而直接使用return -1;然後在我們的那個線程管理類裏
while裏寫一個條件如果函數指針返回爲-1我就要退出全部的線程啦!這樣就基本上可能做爲一個類來使用了。
就以前的一些問題修改了一下。
1、增加了可以直接繼承的一個虛函數;
2、爲NotifyProcess函數增加了一個等待事件,可能保證每次的NotifyProcess調用之後,這個線程都會要工作一次。