C++基本线程的管理《C++多线程编程实战》

由于VS2017编译器的问题,本次开发环境在QT5.7.0.0下

CThread项目:

  • CThread.h
#ifndef CTHREAD_H
#define CTHREAD_H

#include <windows.h>
//#include <Windows.h>

const int STATE_RUNNING	=       0x0001; //设置运行标志, 说明线程正在运行
const int STATE_READY =			0x0002;	//设置就绪状态, 说明线程正在加入调用方
const int STATE_BLOCKED	=		0x0004;	//设置阻塞标志, 说明线程被挂起
const int STATE_ALIVE =			0x0008;	//设置激活标志, 说明线程被创建
const int STATE_ASYNC =			0x0010;	//设置异步标志, 说明线程将并发执行, 即在线程返回之前, 调用方不会阻塞线程
const int STATE_SYNC =			0x0020;	//设置同步标志, 说明线程将不会并发执行, 即调用方在线程返回之前将一直阻塞
const int STATE_CONTINUOUS =	0x0040;	//设置连续标志, 说明线程将连续工作永不停止, 或者至少在进程退出前一直运行

//需要执行同步时用到该类
class CLock
{
public:
    CLock();
    ~CLock();
private:
    HANDLE hMutex;
};

class CThread
{
public:
    CThread() : hThread(0), dwThreadId(0), dwState(0),
        lpUserData(0), lpParameter(0) { }
    HANDLE Create(LPVOID lpParameter,
        DWORD dwInitialState = STATE_ASYNC, DWORD dwCreationFlag = 0); //创建实际的线程
    void Join(DWORD dwWaitinterval = INFINITE);
    DWORD Suspend();
    DWORD Resume();
    void SetUserData(void* lpUserData);
    void* GetUserData() const;
    DWORD GetId() const;
    HANDLE GetHandle() const;
    DWORD GetAsyncState() const;
    DWORD GetState() const;
    void SetState(DWORD dwNewState);
    BOOL Alert();

protected:
    virtual void Run(LPVOID lpParameter = 0) = 0; //为了派生类用
    LPVOID lpParameter;

private:
    //必须为static, 因为第1个参数都是隐式参数this(即不显示)
    static DWORD WINAPI StartAddress(LPVOID lpParameter);

    HANDLE hThread;
    DWORD dwThreadId;
    DWORD dwState;
    void* lpUserData;
    HANDLE hEvent;
};

//返回一个唯一的线程标识
inline DWORD CThread::GetId() const
{
    return dwThreadId;
}

//返回一个线程句柄
inline HANDLE CThread::GetHandle() const
{
    return hThread;
}

#endif // CTHREAD_H


  • CThread.cpp
#include "CThread.h"

//如果另有线程也需要互斥量, 那么在互斥量释放之前, 这个需要互斥量的线程将被阻塞
CLock::CLock()
{
    //第二个参数为FALSE, 一旦创建了一个互斥量, 该线程就不再拥有其所有权
    hMutex = CreateMutex(NULL, FALSE, TEXT("_tmp_mutex_lock_"));
    WaitForSingleObject(hMutex, INFINITE); //调用此函数才能拥有互斥量的所有权
}

CLock::~CLock()
{
    ReleaseMutex(hMutex); //释放互斥量
    CloseHandle(hMutex);  //关闭互斥量的句柄
}

//第一个参数必须的, 稍后该参数将被传给StartAddress,线程从这里开始执行
//第二个参数代表线程执行方法, 如果设置为STATE_SYNC, 就使用CLock类对象
//第三参数设置线程状态: 默认0表示创建该线程后立即使用它
//	                    STATE_BLOCKED创建一个处于挂起状态的线程
//	                    STATE_CONTINUOUS创建事件,若存在则打开事件对象
HANDLE CThread::Create(LPVOID lpParameter, DWORD dwInitialState,
    DWORD dwCreationFlag)
{
    dwState |= dwInitialState;
    this->lpParameter = lpParameter;
    if (dwState & STATE_ALIVE)
    {
        return hThread;
    }
    hThread = CreateThread(NULL, 0, StartAddress, this,
        dwCreationFlag, &dwThreadId);
    dwState |= STATE_ALIVE;
    if (dwState & STATE_CONTINUOUS)
    {
        hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("__tmp_event__"));
    }

    return hThread;
}

//设置STATE_READY标志, 并等待线程对象成为已触发状态
//或在dwWaitInterval时间间隔内一直等待
//dwWaitInterval默认INFINITE
void CThread::Join(DWORD dwWaitInterval)
{
    if (dwState & STATE_BLOCKED)
    {
        return;
    }
    if (dwState & STATE_READY)
    {
        return;
    }
    dwState |= STATE_READY;
    WaitForSingleObject(hThread, dwWaitInterval);
    dwState ^= STATE_READY;
}

//挂起线程
//设置STATE_BLOCKED
DWORD CThread::Suspend()
{
    if (dwState & STATE_BLOCKED)
    {
        return DWORD(-1);
    }
    if (dwState & STATE_READY)
    {
        return DWORD(-1);
    }

    DWORD dwSuspendCount = SuspendThread(hThread);
    dwState |= STATE_BLOCKED;

    return dwSuspendCount;
}

//恢复线程
//复原STATE_BLOCKED
DWORD CThread::Resume()
{
    if (dwState & STATE_RUNNING)
    {
        return DWORD(-1);
    }
    DWORD dwSuspendCount = ResumeThread(hThread);
    dwState ^= STATE_BLOCKED;

    return dwSuspendCount;
}

//设计lpUserData,为了将来方便设置用户指定的数据
//设置用户的数据值
void CThread::SetUserData(void* lpUserData)
{
    this->lpUserData = lpUserData;
}
//获取用户的数据值
void* CThread::GetUserData() const
{
    return lpUserData;
}

//返回对象的异步状态
DWORD CThread::GetAsyncState() const
{
    if (dwState & STATE_ASYNC)
    {
        return STATE_ASYNC;
    }
    return STATE_SYNC;
}

//处理额外的对象状态
//获取dwState值或对象状态
DWORD CThread::GetState() const
{
    return dwState;
}
//设置dwState值或对象状态
void CThread::SetState(DWORD dwNewState)
{
    dwState = 0;
    dwState |= dwNewState;
}

//把事件的状态改为signaled
//处理使用了STATE_CONTINUOUS情况
BOOL CThread::Alert()
{
    return SetEvent(hEvent);
}

DWORD WINAPI CThread::StartAddress(LPVOID lpParameter)
{
    CThread* cThread = (CThread*)lpParameter;
    if (STATE_SYNC == cThread->GetAsyncState())
    {
        if (cThread->dwState & STATE_CONTINUOUS)
        {
            DWORD dwWaitStatus = 0;
            while (TRUE)
            {
                cThread->Run();

                dwWaitStatus = WaitForSingleObject(cThread->hEvent, 10);

                if (WAIT_OBJECT_0 == dwWaitStatus)
                {
                    break;
                }
            }

            return 0;
        }

        cThread->Run();
        return 0;
    }

    if (cThread->dwState & STATE_CONTINUOUS)
    {
        DWORD dwWaitStatus = 0;
        while (TRUE)
        {
            CLock lock;
            {
                cThread->Run();
            }

            dwWaitStatus = WaitForSingleObject(cThread->hEvent, 10);

            if (WAIT_OBJECT_0 == dwWaitStatus)
            {
                break;
            }
        }
        return 0;
    }

    //多此一举了,去掉大括号一样的意义
    CLock lock;
    {
        cThread->Run();
    }

    return 0;
}


  • main.cpp
#include "CThread.h"

class Thread : public CThread
{
protected:
    virtual void Run(LPVOID lpParameter = 0);
};

LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        break;
    }
    case WM_CLOSE:
    {
        DestroyWindow(hWnd);
        break;
    }
    default:
    {
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    }

    return 0;
}

//纯虚函数 使其行为更像一个非静态方法
void Thread::Run(LPVOID lpParameter)
{
    WNDCLASSEX wndEx = { 0 };

    wndEx.cbClsExtra = 0;
    wndEx.cbSize = sizeof(WNDCLASSEX);
    wndEx.cbWndExtra = 0;
    wndEx.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
    wndEx.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wndEx.hInstance = GetModuleHandle(NULL);
    wndEx.lpfnWndProc = WindowProcedure;
    wndEx.lpszClassName = (LPCTSTR)this->lpParameter;
    wndEx.lpszMenuName = NULL;
    wndEx.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

    if (!RegisterClassEx(&wndEx))
    {
        return;
    }

    HWND hWnd = CreateWindow(wndEx.lpszClassName, TEXT("Basic Thread Management"), WS_OVERLAPPEDWINDOW,
        200, 200, 800, 600, HWND_DESKTOP, NULL, wndEx.hInstance, NULL);

    UpdateWindow(hWnd);
    ShowWindow(hWnd, SW_SHOW);

    MSG msg = { 0 };
    while (GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    UnregisterClass(wndEx.lpszClassName, wndEx.hInstance);
}

int main()
{
    Thread thread;
    thread.Create((LPVOID)TEXT("WND_CLASS_1"));

    Thread pthread;
    pthread.Create((LPVOID)TEXT("WND_CLASS_2"));

    thread.Join();
    pthread.Join();

    return 0;
}


  • 运行结果:需要关闭2次
    在这里插入图片描述

版权声明:本文为qq_33373173原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。