专栏首页Windows开发一个简单实用的线程基类

一个简单实用的线程基类

独立子线程设计 这篇文章介绍了在无法控制子线程生命周期时应该怎么做。

这篇文章介绍线程基类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);
}

本文分享自微信公众号 - Windows开发(gh_5216ec78fc5b),作者:kinglon

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-08-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 系统学习Windows客户端开发

    gaigai
  • 完整部署运行时库

    运行时库是软件运行时必需依赖的一系列DLL,最常见的是VC运行时库(比如msvcrt.dll),如果有用到MFC还需要依赖MFC库。

    gaigai
  • 高效查看日志排错

    免费软件Notepad++是一款功能强大的文本编辑器,其支持使用正则表达式查找,使用方法:选择菜单栏搜索 -> 选择子菜单查找,弹出查找窗口,输入查找目标,查找...

    gaigai
  • 你需要了解的有关 Node.js 的所有信息

    Node.js 是当前用来构建可扩展的、高效的 REST API's 的最流行的技术之一。它还可以用来构建混合移动应用、桌面应用甚至用于物联网领域。

    五月君
  • 线程池

    线程池的作用: 线程池作用就是限制系统中执行线程的数量。      根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,...

    汤高
  • JMeter(连载2)

    接下来就可以用JMeter修改录制和脚本了,在修改之前,介绍一下一些最基本的组件功能。由于JMeter功能非常强大并且支持很多控件,所以介绍所有的组件是不可能的...

    小老鼠
  • Python的线程与进程

    看过《Python分布式计算》,觉得线程和进程,最大的区别还是在于 —— 二者是如何与内存交互的。线程是共享式的内存架构,进程是分布式的内存架构,这才是问题的...

    SeanCheney
  • 线程和进程

    进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.

    邹志全
  • 进程和线程关系及区别

    一、定义 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。 线程是进程的一个实体,是CPU调度...

    小小科
  • Java concurrency in practice笔记 02 03

    线程安全性的核心是正确性,正确性的含义是如果类的行为与其规范完全一致。因此当多个线程访问某个类时,类的行为始终是安全的,这个类就是线程安全的,...

    Dylan Liu

扫码关注云+社区

领取腾讯云代金券