视频监控应用中可伸缩的线程池设计
在撰写本文前 我有选择性的参考了目前网络上对于线程池的介绍和实现的技术文章。结合自己实践经历,做如下分条阐述。
一.依赖支持:基于通用线程基类。
基于公司内部的线程基础库。线程基类中*为关键的是几个虚继承函数。
//所有的线程都必须重载此方法!!!
virtual void RunBefor()=0; //行动准备
virtual void RunAfter()=0; //撤离准备
virtual void Run()=0; //执行体
其他由基类派生出来的子类 就可以而且必须实现这3个函数。在继承后的函数中 按照自己的功能要求来加以具体实现了。
二.架构剖析:一个管理引擎线程,一群工作线程。
1线程池要有个列表,来管理多个线程对象。
线程池只是一个架子,就像房子要有人才行。有人就会有事情产生和处理。所谓的事情就是一个线程对象,具体线程的run函数就是事情的解决过程逻辑。
2线程池要提供获取空闲(IDLE)线程方法。
这个是非常必要的。一般获取空闲可以用遍历的法子。当然在具体应用中,“空闲”的概念也可以很丰富。比如用某某算法快速定位等等。这里就不展开了。
3线程池中的线程,具体执行的内容,可自定义。
线程池只是一个架子,提供一种模板化的处理建议。至于具体一个新分配的线程究竟做什么,就看程序的应用场景了。
4线程池中的线程,使用完毕后,还能被收回,供下次使用。
所谓线程池,可以理解为一种思想。就像一个水池,多进多出罢了。需要就取,用完归还。
5重复和克隆机制按需使用。
在视频监控的应用场合中,重复和克隆都是很常见且非常有效的处理思维。重复为了减少无谓的开销。克隆为了及时的响应,否则在某一点接入时间点会导致无法接入的情况。相信写服务器的朋友对此应该都深有感触把。
三.调度规则
1、线程的创建
一般当服务器接收到客户端的请求后,会调用线程POOL的一个外调接口函数。
外调函数根据条件判断,遍历绑定的队列,看是否有相同的对象。如果有,则返回失败。
如果没有,则用new操作新建一个线程对象,赋值并Resume。然后线程对象就经有runbefor到run循环中执行特定的处理逻辑,*后经由runafter退出线程。
2、任务分配策略及执行过程
一般在服务端的线程处理引擎中需要好几个线程池合力协作。拿视频监控项目的实践来说。至少会需要接入POOL,处理POOL,呼出POOL。它们每个POOL本身就是一个线程引擎。而相互之间的联系一般通过标记位的方式进行合理的串联,以达到流水工序化作业的目的。一个流程下来,就能非常好的体现出 任务分配的思想。有人负责接待,有人烧菜,有人端菜,有人负责中间协调,有人收拾碗筷,有人送客。俨然一个饭店的流程。
3、线程的销毁
一般线程在主循环run中执行自己的处理逻辑。一旦退出条件被触发,那么置位退出标记为istobeclosed,然后自己空兜线程,就是仅仅sleep(10)然后直接返回。这个时候 负责管理引擎的线程 在查找线程状态时候 发现这个线程想要退出。就调用线程基类的SetStopFlag(),让线程退出去,再等待IsOutRun返回TRUE,再就是delete线程对象。
四.附录代码
(1)线程基类
class CThread
{
public:
CThread();
CThread(bool suspend);
virtual ~CThread();
//以下是常见函数定义;
HANDLE GetHandle();
int GetID();
int GetGroupID();
int GetThreadID();
string GetNickName();
void SetID(int iID);
void SetGroupID(int iGroupID);
void SetNickName(const string& sName);
//zhangxf 2010-01-28补充;
void SetNoSleep();
void SetSleepTime(int ivalue);
void Resume(); //启动线程;
void Suspend(); //挂起线程;
bool Wait(long TimeToStop,bool bWaitAllTime=false); //等待线程退出主循环体
void SetStopFlag(bool IsStopFlag);//子类协同性退出
bool GetStopFlag();//获取退出标记
bool IsDead();//线程是否僵死
DWORD GetLastRunTime();//获取上次循环体进入时间
DWORD GetLastSuspendedTime();//获取上次挂起时间
DWORD GetLastResumeTime();//获取上次唤醒时间
bool IsSuspended();
bool IsOutOfRun();
void Terminate();//强制退出
//获取错误码
int GetLastError() const {return m_ErrorCode;}
//所有的线程都必须重载此方法!!!
virtual void RunBefor()=0; //行动准备
virtual void RunAfter()=0; //撤离准备
virtual void Run()=0; //执行体
void MainRun();
protected:
static unsigned _stdcall ThreadEntry(LPVOID lpParam);
private:
HANDLE m_hThread; //线程句柄
int m_ID;
int m_ThreadID; //线程ID
int m_GroupID; //线程组别;
string m_NickName; //线程名称;
DWORD m_LastRunTime; //上次循环体进入时间
DWORD m_LastSuspendedTime;//上次挂起的时间
DWORD m_LastResumeTime; //上次唤醒的时间
bool m_IsSuspended; //目前线程的状态是否挂起;
int m_ErrorCode;
bool m_IsTerminated; //线程是否终止
bool m_IsOutOfRun; //是否退出了主循环
int m_SleepTime; //设置sleep的秒数;
};
(2)线程池参考范例
//视频发送线程
class CVideoSend : public CThread
{
public:
CVideoSend(bool CreateSuspended);
~CVideoSend();
void RunBefor();
void RunAfter();
void Run();
public:
bool _RunProc(); //加返回值gzb 2010-09-08
void _RunBefor(); //内部函数
public:
void Binding(CPublicInfo* _PublicInfo);
void Binding(CVideoSendPool* _VideoSendPool);
public:
CPublicInfo* m_Binding_PublicInfo; //由publicinfo绑定路由列表
CVideoSendPool* m_Binding_VideoSendPool; //绑定发送线程pool
public:
CVideoShare* m_Binding_VideoShare; //绑定 视频共享内存区指针。
CNetContext* m_Binding_TContext; //绑定请求的包文
CNetTCPClient* m_Package_NetClient; //包装一个CNetTCPClient,没有实质的去新建。
int m_WriteIndex; //
DWORD m_WriteTime; //
CCmdContext* m_CmdContext; //请求包文指针-----------------------
SOCKET m_SocketID; //SocketID
string m_ClientIP; //客户端IP
WORK_STATE m_WorkState; //状态
string m_GUID; //**标记。gzb 2010-08-26
};
typedef std::list<CVideoSend*> _CVideoSendList;
////
class CVideoSendPool : public _CVideoSendList,public CThread
{
public:
CVideoSendPool(bool CreateSuspended);
~CVideoSendPool();
void RunBefor();
void RunAfter();
void Run();
public:
void _RunProc();
public:
//取空闲线程;
void Binding(CPublicInfo* _PublicInfo);
void _FindNoLivingAndDelete(); //定期清理
void _PrintfPoolInfo();
public:
bool NL_StartSendVideo();
bool out_RequestForVideo();
public:
CPublicInfo* m_Binding_PublicInfo; //
};
杭州锐虎科技 研发部
锐虎科技,专注安防监控平台软件设计
联系人:王先生
联系电话:
手机:
QQ:843362323
E-mail: wangyj@rihvision.com
联系人:肖先生
联系电话:
手机:
QQ:11834450
E-mail: xiaocb@rihvision.com
网址:http://www.rihvision.com