一个简单的线程类

来源:互联网 发布:查看linux下tomcat版本 编辑:程序博客网 时间:2024/04/19 19:27

有不少的时候,我们都需要一个这样的线程类来管理我们的线程。

现在我做一个最简单的一个线程管理类。

我们的这个线程当然会开始一个线程。并且会让用户能写一个线程处理函数加到我的这个类里来。

所以这个会要从外部读入一个处理函数的一个函数指针给我。

自己写这个处理函数的时候会需要入口参数,这里我设计使用一个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调用之后,这个线程都会要工作一次。