qt多线程实例_Windows下C++多线程管理类

Windows下C++多线程管理类

windows下通过手动调用WIN32 API里的CreateThread这些函数来管理线程,还需要管理线程同步,着实不方便。借鉴Qt中的QThread的思路。自定义一个CThread,作为线程对象的基类。

以下是Thread.h的代码

#pragma once
#include <exception>
#include <WinBase.h>

class CThread;

//定义了CThread类的Priority属性的可能值,如下所述。根据优先级确定每个线程CPU周期
enum CThreadPriority
{
    tpIdle = THREAD_PRIORITY_IDLE,                   //只有当系统空闲时该线程执行
    tpLowest = THREAD_PRIORITY_LOWEST,               //线程优先线比正常低2点
    tpLower = THREAD_PRIORITY_BELOW_NORMAL,          //线程优先线比正常低1点
    tpNormal = THREAD_PRIORITY_NORMAL,               //线程优先线比正常低
    tpHigher = THREAD_PRIORITY_ABOVE_NORMAL,         //线程优先线比正常高1点
    tpHighest = THREAD_PRIORITY_HIGHEST,             //线程优先线比正常高2点
    tpTimeCritical = THREAD_PRIORITY_TIME_CRITICAL   //线程优先线最高
};


//线程通知消息类
class CThreadNotifyEvent
{
public:
    //当线程的Execute方法已经返回且在该线程被删除之前发生
    virtual void OnTerminate(CThread *thread) = 0;
    //当线程发生异常时发生
    virtual void OnException(std::exception &e) = 0;
};


// CThread是一个抽象类,可以创建几个独立的线程
// 每一新子类的CThread对象的实例是一个新的线程。从CThread派生的多线程实例可以构成多线程应用程序
// 当一个应用程序运行时,应用程序就被载入内准备执行。此时,它成为包含一个或多个线程的进程,每个
// 线程含有数据、代码和系统资源。线程执行应用程序的部分内容,并由系统分配CPU时间。同一进程的所
// 有线程共享同一地址空间,可以访问进程的全局变量。线程通过以下工作改善应用的性能:
// 管理多通信设备的输入
// 区分任务的优先级。优先级高的处理紧争的任务,优先级低的处理其他任务
// 以下是使用线程的一些建议:
// 同时跟踪太多的线程消耗CPU时间。对单处理器系统,一个进程最多有16个线程
// 当多个线程更新相同的资源时,应使线程同步以避免冲突
// 大多数访问系统对象和更新窗体的方法必须从主系统线程内部调用
class CThread
{
public:
    //创建一个线程对象的实例,并挂起。Execute直到Resume调用后才被调用
    CThread();
    virtual ~CThread();

    bool IsActive();  //线程是否已经激活

    bool IsTerminated();  //如果IsTerminated == true说明进程要求该线程中止。

    bool Resume();  //重新执行一个挂起的线程。成功返回true;

    bool Suspend();  //挂起一个运行中的线程。成功返回true;

    void Terminate(); //终止线程

    void Wait();      //等待线程结果

    HANDLE GetHandle();  //返回线程句柄

    CThreadPriority GetPriority();//返回线程优先级

    void SetPriority(CThreadPriority priority); //设置该线程相对于进程中其他线程的优先级

    void Attach(CThreadNotifyEvent *event); //注册线程通知消息event

    //设置信号量,相当于UnLock
    void SetEvent();

    //释放信号量,相当于Lock
    void ResetEvent();

protected:
    //Execute模板
    //while (!IsTerminated())
    //{
    //  Wait();  //等待事件有信号状态(unlocked)
    //  if (IsTerminated())  //需要再次判断,因为Wait之后,IsTerminated可能返回了true
    //      return;
    //  ResetEvent();  //将信号设置成无信号状态(Lock),根据实际情况,也可以不加锁
    //  // TODO: Add your code here
    //  SetEvent();  //将信号设置成有信号状态(Unlock),根据实际情况,和上面的加锁匹配
    //}
    virtual void Execute() = 0;
private:
    CThreadNotifyEvent *m_threadNotifyEvent;   //观察者
    HANDLE m_hHandle;     //线程句柄
    HANDLE m_hWaitEvent;  //事件对象句柄
    DWORD m_dwThreadID;   //线程ID
    bool m_bActive;       //标识线程是否处于激活状态
    bool m_bTerminated;   //标识是否需要结束线程

    //!所有线程必须从一个指定的函数开始执行,该函数称为线程函数,它必须具有下列原型:
    static DWORD WINAPI ThreadProc(LPVOID lpvThreadParm);
};

接着是Thread.cpp

#include "stdafx.h"
#include "Thread.h"


typedef unsigned(__stdcall *PTHREAD_START) (void *);


CThread::CThread()
{
    m_threadNotifyEvent = nullptr;
    m_bTerminated = false;
    m_bActive = false;
    m_dwThreadID = 0;

    m_hHandle = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START)ThreadProc,
        this, CREATE_SUSPENDED, (unsigned *)&m_dwThreadID);
    if (m_hHandle == nullptr)
    {
        char msg[64];
        sprintf_s(msg, "Create thread failed with error code %d.n", GetLastError());
        throw std::exception(msg);
    }

    //安全属性:NULL, 复位方式:手动, 初始状态:有信号状态
    m_hWaitEvent = ::CreateEvent(nullptr, TRUE, TRUE, NULL);
    if (m_hWaitEvent == nullptr)
    {
        char msg[64];
        sprintf_s(msg, "Create event failed with error code %d.n", GetLastError());
        throw std::exception(msg);
    }
}


CThread::~CThread(void)
{
    this->Terminate();

    ::CloseHandle(m_hWaitEvent);
    ::CloseHandle(m_hHandle);
}


bool CThread::IsActive()
{
    return m_bActive;
}


bool CThread::IsTerminated()
{
    return m_bTerminated;
}


bool CThread::Resume(void)
{
    if (m_bActive)
        return true;

    if (::ResumeThread(m_hHandle) == -1)
    {
        char msg[128];
        sprintf_s(msg, "Resume thread failed with error code %d.n", GetLastError());
        throw std::exception(msg);
        return false;
    }

    m_bActive = true;
    return true;
}


bool CThread::Suspend(void)
{
    if (!m_bActive)
        return true;

    if (SuspendThread(m_hHandle) == -1)
    {
        char msg[128];
        sprintf_s(msg, "Suspend thread failed with error code %d.n", GetLastError());
        throw std::exception(msg);
        return false;
    }
    m_bActive = false;
    return true;
}


void CThread::Terminate()
{
    //这里加锁,确保调用Terminate函数之后,Execute函数能够立即停止运行
    Wait();
    ResetEvent();  //Lock
    m_bTerminated = true;
    SetEvent();  //Unlock,设置成有信号状态
}


void CThread::Wait()
{
    //函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去
    ::WaitForSingleObject(m_hWaitEvent, INFINITE);
}


HANDLE CThread::GetHandle()
{
    return m_hHandle;
}


CThreadPriority CThread::GetPriority()
{
    return (CThreadPriority)GetThreadPriority(m_hHandle);
}


void CThread::SetPriority(CThreadPriority priority)
{
    SetThreadPriority(m_hHandle, priority);
}


void CThread::Attach(CThreadNotifyEvent *event)
{
    m_threadNotifyEvent = event;
}


void CThread::SetEvent()  //Unlock
{
    ::SetEvent(m_hWaitEvent);
}


void CThread::ResetEvent()  //Lock
{
    ::ResetEvent(m_hWaitEvent);
}


DWORD WINAPI CThread::ThreadProc(LPVOID lpvThreadParm)
{
    CThread *thread = (CThread*)lpvThreadParm;
    CThreadNotifyEvent *event = thread->m_threadNotifyEvent;

    try
    {
        thread->Execute();
    }
    catch (std::exception &e)
    {
        if (event)
            event->OnException(e);
    }

    try
    {
        if (event)
            event->OnTerminate(thread);
    }
    catch (std::exception &e)
    {
        if (event)
            event->OnException(e);
    }

    return 0;
}

接下来是用法

比如,我们创建了一个MFC对话框应用程序,需要接收串口消息。我截取关键代码。

  1. 对话框类继承上述CThread类,并重写Execute函数,头文件主要代码如下:
class CDemoDlg : public CDialogEx, CThread
{
//省略其他代码
//从CThread中继承的虚函数
protected:
    virtual void Execute() override;
}
  1. 重写Execute函数,cpp文件主要代码如下
void CDemoDlg::Execute()
{
    //模板
    while (!IsTerminated())
    {
        Wait();  //等待事件有信号状态(unlocked)
        if (IsTerminated())  //需要再次判断,因为Wait之后,IsTerminated可能返回了true
            return;
        ResetEvent();  //将信号设置成无信号状态(Lock),根据实际情况,也可以不加锁

        // TODO: Add your code here
        //省略需要反复执行的代码
        Sleep(1);

        SetEvent();  //将信号设置成有信号状态(Unlock),根据实际情况,和上面的加锁匹配
    }
}

注意:上述Execute函数中,最后有一个Sleep(1);这句代码可有效降低CPU占用,可以根据实际情况增大时间间隔,当然在我的实际情况下,时间间隔的大小对CPU占用率影响不大。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值