在开发多线程程序时,常常碰到线程管理的问题。当有多种线程的时候,为了控制每个线程,编程工作也变得复杂。事实上,我们对线程的控制大多是相似的,所以把这些控制抽象出来,形成一个可复用的程序模块,将能大大提高开发效率和代码质量。
首先我们对线程的使用目的进行分析和归纳。一般来说,有如下几种:
1) 独立线程。执行一项在后台完成的工作,工作频率很低,线程的生命期里只完成一项任务。线程基本上不需要什么管理。
2) 定时线程。线程每隔一段时间,定时执行一定的功能,可能是查看某一状态,或输出某种信息。线程要设定时间间隔,并且需要显式地中止才会结束。
3) 守护线程。线程等待某事的发生,当事件发生时开始工作,完成后继续进行等待状态。因为事件发生的非常频繁时,使用守护线程以避免独立线程会带来的太多的线程开销。线程要能随时启动,也需要显式地中止才会结束。
所以线程管理需要完成以下功能:
1) 等待。当工作完成时,自动进入等待状态,而不是中止。
2) 定时执行。等待某一时间后,能自动执行。
3) 调用执行。当事件发生时,能继续执行。
4) 中止。正常地结束,把任务处理完,中止线程。
设计一个具有以上管理功能的线程并不困难,但为每一个线程都写一段这样的代码就显得很麻烦了,更何况这些代码其实都是类似的。为此,笔者设计了一个线程管理类,把线程的工作函数放入线程管理的框架内执行。线程的工作函数不再是线程的开始入口,而仅被作为一个函数被调用。
类的声明如下:
class
CThreadMaster
{
public
:
CThreadMaster(
void
);
~
CThreadMaster(
void
);
typedef
void
(
*
WorkFuncType)(
void
*
param);
enum
CycleTimeEnum{ AlwaysWait
=
-
1
, AlwaysWork
=
0
};
void
Start();
void
Stop();
void
WorkNow();
void
Set(WorkFuncType function,
void
*
parameter,
int
cycleTime);
void
SetWorkFunction( WorkFuncType function );
void
SetWorkParameter(
void
*
parameter);
void
SetCycleTime(
int
cycleTime );
unsigned
long
GetThreadId();
static
unsigned __stdcall WorkThread(
void
*
lpParameter );
protected
:
enum
ThreadCmd{ nothing
=
0
, stop};
ThreadCmd m_ThreadCmd;
HANDLE m_hThread;
HANDLE m_hEvent;
unsigned
int
m_ThreadId;
int
m_CycleTime;
void
*
m_lpParameter;
WorkFuncType m_WorkFunction;
};
函数
void
Set(WorkFuncType function, void * parameter, int cycleTime);
用来设置线程的工作函数、工作参数、和工作周期,参数如下:
function:工作函数的指针;
parameter:工作函数的参数;
cycleTime:工作函数的执行周期期,可以是一个正整数的时间值,单位为1/1000秒,也可以是如
CycleTimeEnum
定义的两个特殊值:
enum
CycleTimeEnum{ AlwaysWait = -1, AlwaysWork = 0};
cycleTime的值为AlwaysWait表示执行完工作函数以后,线程一直等待,直到WorkNow函数被调用,或线程被Stop函数中止;
cycleTime的值为AlwaysWork表示不停地循环调用工作函数。
如果cycleTime为其它正值,那么执行完工作函数之后,等待cycleTime指定的时长并重新调用工作函数。如果在等待期间调用了WorkNow,那么工作函数将立刻被执行。
函数
Start()
、Stop()用来启动的中止线程,WorkNow()用来使线程进入工作状态,多次调用WorkNow不会影响工作状态。
使用这个类,我们只要把线程函数定义为
WorkFuncType
类型的静态函数,然后调用CThreadMaster类实例的Set函数设置该函数的指针、参数、和工作状态,就可以使用CThreadMaster提供的控制函数来管理线程了。线程所有的工作都会安全地开始,并优雅地结束。CThreadMaster实例销毁时,也会自动结束线程。
现把这个类的实现代码放到下面,以供参考, CThreadMaster.cpp:
#include
<
process.h
>
#include
"
. hreadmaster.h
"
CThreadMaster::CThreadMaster(
void
)
...
{
m_ThreadCmd = nothing;
m_hThread = NULL;
m_hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
m_ThreadId = 0;
m_CycleTime = AlwaysWork;
m_WorkFunction = NULL;
m_lpParameter = NULL;
}
CThreadMaster::
~
CThreadMaster(
void
)
...
{
Stop();
CloseHandle(m_hEvent);
}
void
CThreadMaster::Start()
...
{
if (m_ThreadId!=0)
return;
m_ThreadCmd = nothing;
m_hThread = (HANDLE)_beginthreadex(NULL,0, WorkThread, (void *)this, 0, &m_ThreadId);
}
void
CThreadMaster::Stop()
...
{
if (m_ThreadId==0)
return;
m_ThreadCmd = stop;
WorkNow();
WaitForSingleObject(m_hThread, INFINITE);
m_ThreadCmd = nothing;
m_ThreadId = 0;
m_hThread = NULL;
}
void
CThreadMaster::WorkNow()
...
{
if (m_hThread==0)
...{
Start();
SetEvent(m_hEvent);
}else
SetEvent(m_hEvent);
}
unsigned CThreadMaster::WorkThread(
void
*
lpParameter )
...
{
CThreadMaster * pThis = (CThreadMaster*) lpParameter;
if (pThis==NULL)
return -1;
for(;;)
...{
if (pThis->m_CycleTime > AlwaysWork)
WaitForSingleObject(pThis->m_hEvent, pThis->m_CycleTime);
else if (pThis->m_CycleTime<=AlwaysWait)
WaitForSingleObject(pThis->m_hEvent, INFINITE);
if (pThis->m_ThreadCmd==stop)
return 0;
if (pThis->m_WorkFunction!=NULL)
...{
try...{
(*pThis->m_WorkFunction)(pThis->m_lpParameter);
}catch (...)...{
}
}
}
return -2;
}
void
CThreadMaster::Set(WorkFuncType function,
void
*
parameter,
int
cycleTime)
...
{
m_WorkFunction = function;
m_lpParameter = parameter;
m_CycleTime = cycleTime;
}
void
CThreadMaster::SetWorkFunction( WorkFuncType function )
...
{
m_WorkFunction = function;
}
void
CThreadMaster::SetWorkParameter(
void
*
parameter)
...
{
m_lpParameter = parameter;
}
void
CThreadMaster::SetCycleTime(
int
cycleTime )
...
{
m_CycleTime = cycleTime;
}
unsigned
long
CThreadMaster::GetThreadId()
...
{
return m_ThreadId;
}