電腦網路實驗要求寫一個檔案傳輸程式。由於以前自己寫的線程類和SOCKET類丟失掉了(寢室電腦被盜),現在重寫這幾個類,乾脆就寫了一個線程池,用的是C++STL和純API。而且,為了保證這個線程類本身是安全執行緒的,我還使用了WinApi中的互斥量。同時仿照C#的類庫,線上程類中加入了Join方法。調用線程對象Join方法的線程將等待線程對象直到執行完畢。以下是原始碼。
/////////////////////////////////MyThread.h//////////////////////////////////////
#ifndef _MYTHREAD_H_
#define _MYTHREAD_H_
#include "MyException.h"
#include <windows.h>
#include <list>
using namespace std;
//前向聲明
class CMyThread;//線程類
class CMyThreadPool;//線程池類
class CMyThreadExp;//線程異常類
#define MyThreadProc LPTHREAD_START_ROUTINE
//線程狀態枚舉
enum MyThreadStatus
{
THREADRUN,//運行
THREADPAUSE,//暫停
};
//線程類,可動態更換執行函數
class CMyThread
{
struct MyThreadParam
{
LPTHREAD_START_ROUTINE proc;//使用者線程函數
void *lpParam;//使用者線程參數
CMyThread *pCMyThread;//線程類對象
};
public:
//構造,proc線程函數
CMyThread();
//析構
~CMyThread();
//運行線程
bool Run();
//暫停線程
bool Pause();
//調用Join的線程將阻塞,直到該線程執行完畢
void Join();
//設定線程啟動並執行函數,和要傳給線程的參數
void SetProc(LPTHREAD_START_ROUTINE proc, void* lpParam);
protected:
CMyThread(CMyThread&) {}
//線程實際啟動並執行函數
static DWORD WINAPI RealThreadProc(void* lpParam);
friend class CMyThreadPool;
protected:
HANDLE m_hThread;
DWORD m_id;
HANDLE m_hEvt;
MyThreadParam m_param;
MyThreadStatus m_status;
HANDLE m_hMtx;
};
//線程池類
class CMyThreadPool
{
public:
//構造,initNum初始情況線程數量
CMyThreadPool(int initNum);
//析構
~CMyThreadPool();
//申請線程進行工作,proc工作函數,lpParam工作函數參數,run是否立即運行,返回線程ID
DWORD DoWork(LPTHREAD_START_ROUTINE proc, void *lpParam, bool run=true);
//運行線程,id線程ID
bool Run(DWORD id);
//暫停運行線程,id線程ID
bool Pause(DWORD id);
//調整線程池大小為size,返回調整後線程池大小
unsigned SetSize(unsigned size);//when decrease num, its dangerous
protected:
list<CMyThread*> m_lst;
};
//線程異常種類枚舉
enum EnumMyThreadExp
{
EXPCREATETHREAD = 0,
EXPTERMINATETHREAD,
EXPRESUMETHREAD,
EXPSUSPENDTHREAD,
EXPCREATEEVENT,
EXPCREATEMUTEX,
};
//線程異常類
class CMyThreadExp : public CMyException
{
public:
CMyThreadExp(EnumMyThreadExp exp, CMyThread *pobj);
~CMyThreadExp();
void GetInfo();
EnumMyThreadExp m_exp;
CMyThread *m_pobj;
};
#endif//_MYTHREAD_H_
//////////////////////MyThread.cpp//////////////////////////////////
#include "mythread.h"
#include <iostream>
using namespace std;
CMyThreadExp::CMyThreadExp(EnumMyThreadExp exp, CMyThread *pobj)
: m_exp(exp), m_pobj(pobj)
{
GetInfo();
ShowExp();
}
CMyThreadExp::~CMyThreadExp()
{
}
void CMyThreadExp::GetInfo()
{
sprintf(m_strInfo, "/nCMyThread Exception When %p Execute ", (void*)(m_pobj));
switch (m_exp)
{
case EXPCREATETHREAD: strcat(m_strInfo, "CreateThread()"); break;
case EXPTERMINATETHREAD: strcat(m_strInfo,"TerminateThread()"); break;
case EXPRESUMETHREAD: strcat(m_strInfo, "ResumeThread()"); break;
case EXPSUSPENDTHREAD: strcat(m_strInfo, "SuspendThread()"); break;
case EXPCREATEEVENT: strcat(m_strInfo, "CreateEvent()"); break;
case EXPCREATEMUTEX: strcat(m_strInfo, "CreateMutex()"); break;
}
char temp[100];
sprintf(temp, "/nError Code = %d", GetLastError());
strcat(m_strInfo, temp);
}
/**********************************************************************************************/
CMyThread::CMyThread()
: m_hThread(NULL), m_status(THREADPAUSE), m_hEvt(0), m_hMtx(0)
{
m_hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)(CMyThread::RealThreadProc),
(void*)&m_param, CREATE_SUSPENDED, &m_id);
if (m_hThread == NULL)//fail to create thread
{
CMyThreadExp(EXPCREATETHREAD, this);
throw;//construct exception
}
m_param.proc = NULL;
m_param.lpParam = NULL;
m_param.pCMyThread = this;
m_hEvt = CreateEvent(0, FALSE, FALSE, 0);//自動複位
if (m_hEvt == 0)
{
CloseHandle(m_hThread);
CMyThreadExp(EXPCREATEEVENT, this);
throw;//construct exception
}
m_hMtx = CreateMutex(0, 0, 0);
if (m_hMtx == 0)//fail to create mutex
{
unsigned long i = GetLastError();
CloseHandle(m_hEvt);
CloseHandle(m_hThread);
CMyThreadExp(EXPCREATEMUTEX, this);
throw;//construct exception
}
}
CMyThread::~CMyThread()
{
CloseHandle(m_hMtx);
if (TerminateThread(m_hThread, -1) == 0)//fail to terminate
CMyThreadExp(EXPTERMINATETHREAD, this);
}
bool CMyThread::Run()
{
WaitForSingleObject(m_hMtx, INFINITE);//get mutex
if (m_status == THREADPAUSE)
if (ResumeThread(m_hThread) == -1)//fail to resume
{
CMyThreadExp(EXPRESUMETHREAD, this);
ReleaseMutex(m_hMtx);//release mutex
return false;
}
m_status = THREADRUN;
ReleaseMutex(m_hMtx);//release mutex
return true;
}
bool CMyThread::Pause()
{
WaitForSingleObject(m_hMtx, INFINITE);//get mutex
if (m_status == THREADRUN)
if (SuspendThread(m_hThread) == -1)//fail to suspend
{
CMyThreadExp(EXPSUSPENDTHREAD, this);
ReleaseMutex(m_hMtx);//release mutex
return false;
}
m_status = THREADPAUSE;
ReleaseMutex(m_hMtx);//release mutex
return true;
}
void CMyThread::Join()
{
WaitForSingleObject(m_hEvt, INFINITE);
}
void CMyThread::SetProc(LPTHREAD_START_ROUTINE proc, void* lpParam)
{
WaitForSingleObject(m_hMtx, INFINITE);//get mutex
m_param.proc = proc;
m_param.lpParam = lpParam;
ReleaseMutex(m_hMtx);//release mutex
}
DWORD WINAPI CMyThread::RealThreadProc(void* lpParam)
{
LPTHREAD_START_ROUTINE proc;
MyThreadParam *pp = (MyThreadParam*)lpParam;
while (true)
{
proc = pp->proc;
if (proc)
(*proc)(pp->lpParam);
pp->proc = NULL;//clear function
pp->lpParam = NULL;//clear param
pp->pCMyThread->Pause();//pause automatic
SetEvent(pp->pCMyThread->m_hEvt);
}
}
/**********************************************************************************************/
CMyThreadPool::CMyThreadPool(int initNum)
{
CMyThread *pt;
for (int i=0; i<initNum; i++)
{
pt = new CMyThread;
m_lst.push_back(pt);
}
}
CMyThreadPool::~CMyThreadPool()
{
list<CMyThread*>::iterator it = m_lst.begin();
list<CMyThread*>::iterator ite = m_lst.end();
for ( ; it != ite; it++)//terminate all thread
{
delete (*it);
}
}
DWORD CMyThreadPool::DoWork(LPTHREAD_START_ROUTINE proc, void *lpParam, bool run)
{
list<CMyThread*>::iterator it = m_lst.begin();
list<CMyThread*>::iterator ite = m_lst.end();
for ( ; it != ite; it++)//is there a idle thread?
{
if ((*it)->m_param.proc == NULL
&& (*it)->m_status == THREADPAUSE
)
{
(*it)->SetProc(proc, lpParam);
if (run)//run at once
(*it)->Run();
return (*it)->m_id;
}
}
//no idle thread
CMyThread *pt = new CMyThread;//create a new thread
m_lst.push_back(pt);
pt->SetProc(proc, lpParam);
if (run)
pt->Run();
return pt->m_id;
}
bool CMyThreadPool::Run(DWORD id)
{
list<CMyThread*>::iterator it = m_lst.begin();
list<CMyThread*>::iterator ite = m_lst.end();
for ( ; it != ite; it++)
{
if ((*it)->m_id == id)
return ((*it)->Run());
}
return false;
}
bool CMyThreadPool::Pause(DWORD id)
{
list<CMyThread*>::iterator it = m_lst.begin();
list<CMyThread*>::iterator ite = m_lst.end();
for ( ; it != ite; it++)
{
if ((*it)->m_id == id)
return ((*it)->Pause());
}
return false;
}
unsigned CMyThreadPool::SetSize(unsigned size)
{
unsigned nowsize = m_lst.size();
if (nowsize <= size)
{
CMyThread *pt;
unsigned inc = size-nowsize;
for (unsigned i=0; i<inc; i++)
{
pt = new CMyThread;
m_lst.push_back(pt);
}
return size;
}
else
{
unsigned dec = nowsize - size;
list<CMyThread*>::iterator it = m_lst.begin();
list<CMyThread*>::iterator ite = m_lst.end();
list<CMyThread*>::iterator itemp;
unsigned i=0;
for ( ; it!=ite && i<dec; )
{
if ((*it)->m_status == THREADPAUSE)
{
itemp = it++;
delete ((*itemp));
m_lst.erase(itemp);
i++;
continue;
}
it++;
}
Sleep(100*i);
return m_lst.size();
}
}