独立子线程设计 这篇文章介绍了在无法控制子线程生命周期时应该怎么做。
这篇文章介绍线程基类CThreadBase,其将线程资源封装成对象,提供生命周期控制接口,派生类覆盖相应的虚函数进行业务功能实现。
提供接口包括:启动线程Start()、结束线程Stop()、查询运行状态IsRunning()。
启动线程Start(),使用C++11 std::async接口启动线程。
结束线程Stop(),同步接口,线程退出运行时才会返回,有效控制线程的生命周期,同步结束线程对于某些业务场景很重要,比如需要线程结束后才能释放相应的资源。内部使用内核对象Event进行同步。
同时提供三个虚函数供子类覆盖实现:
OnStart()在调用接口Start()后线程运行前调用,其参数strParam是由Start()接口透传过来,在该函数中进行初始化。
OnRun()在线程运行时调用,其参数strParam是由Start接口透传过来,只有OnStart()返回true,才会被调用,线程要处理的工作在该函数中实现。
OnStop()在调用接口Stop()后被调用,该函数重要职责是通知OnRun()退出。
源码包括ThreadBase.h和ThreadBase.cpp,可以复制使用。
ThreadBase.h
#pragma once
#pragma warning ( disable : 4251 )
#include <string>
#include <Windows.h>
#ifndef NDEBUG
#define THREAD_BASE_ASSERT(condition) if (!(condition)) { DebugBreak(); }
#else
#define THREAD_BASE_ASSERT(condition) ((void)0)
#endif
/**
线程基类,提供线程启动(异步)、结束(同步)的功能
*/
class CThreadBase
{
public:
CThreadBase();
virtual ~CThreadBase();
public:
/**
@name 启动线程
@param strParam 透传给OnRun函数
@return 成功 或 失败
*/
bool Start(const std::string& strParam);
/**
@name 同步结束线程
@param strParam 透传给OnRun函数
@return 成功 或 失败
*/
void Stop();
/**
@name 查询是否处于运行中
*/
bool IsRunning();
protected:
//子类可以覆盖,Start时会调OnStart, strParam与Start参数相同
virtual bool OnStart(const std::string& strParam);
//子类可以覆盖,线程启动后会调用OnRun, strParam与Start参数相同
virtual void OnRun(const std::string& strParam);
//子类可以覆盖,线程结束时调用
virtual void OnStop() { }
private:
static void ThreadEntry(CThreadBase* pThis, std::string strParam);
private:
bool m_bRunning = false;
HANDLE m_hSyncStop = NULL;
};
ThreadBase.cpp
#include "ThreadBase.h"
#include <future>
using namespace std;
CThreadBase::CThreadBase()
{
}
CThreadBase::~CThreadBase()
{
if (m_bRunning)
{
THREAD_BASE_ASSERT(false); //should not reach here
Stop();
}
}
bool CThreadBase::Start(const std::string& strParam)
{
if (m_bRunning)
{
THREAD_BASE_ASSERT(false); //should not reach here
Stop();
}
if (!OnStart(strParam))
{
return false;
}
if (m_hSyncStop != NULL)
{
THREAD_BASE_ASSERT(false); //should not reach here
CloseHandle(m_hSyncStop);
}
m_hSyncStop = CreateEvent(NULL, TRUE, FALSE, NULL);
m_bRunning = true;
async(launch::async, &CThreadBase::ThreadEntry, this, strParam);
return true;
}
void CThreadBase::Stop()
{
if (!m_bRunning)
{
return;
}
OnStop();
THREAD_BASE_ASSERT(m_hSyncStop != NULL);
WaitForSingleObject(m_hSyncStop, INFINITE);
CloseHandle(m_hSyncStop);
m_hSyncStop = NULL;
m_bRunning = false;
}
bool CThreadBase::IsRunning()
{
return m_bRunning;
}
bool CThreadBase::OnStart(const std::string& strParam)
{
(void)strParam;
return true;
}
void CThreadBase::OnRun(const std::string& strParam)
{
(void)strParam;
THREAD_BASE_ASSERT(false); //should not reach here
}
void CThreadBase::ThreadEntry(CThreadBase* pThis, std::string strParam)
{
pThis->OnRun(strParam);
THREAD_BASE_ASSERT(pThis->m_hSyncStop != NULL);
SetEvent(pThis->m_hSyncStop);
}