使用Windows API實現自定義線程類CThread

我們在使用QThread的時候,只需要繼承QThread重新實現 run() 函數就可以了,使用起來很方便,接下來就介紹一種實現自定義的類 CThread ,只要繼承 CThread 後,重新實現 run() 函數即可。
關於 QThread 的使用可以參見 使用Qt中的QThread創建線程
或者訪問我的 個人博客主頁 不會飛的紙飛機 ,導航欄中點擊多線程,然後也可以看到這篇文章 使用Qt中的QThread創建線程


首先看一下繼承 CThread 的子類,CalcSumThread (主要實現計算前100個數的和)的實現:
頭文件定義:

#ifndef CALCSUMTHREAD_H
#define CALCSUMTHREAD_H

#include "CThread.h"
class CalcSumThread : public CThread
{
public:
	CalcSumThread();
	~CalcSumThread();
	
	// 重寫run函數,實現計算0~100個數的和
	void run(void) override;
};
#endif

run 函數中的實現:

void CalcSumThread::run(void)
{
	int sum = 0;
	for (int i = 0; i <= 100; ++i)
		sum += i;

	std::cout << "Current Thread ID is " << ::GetCurrentThreadId() << ", Result is " << sum << std::endl;
}

調用部分:

CalcSumThread* thread = new CalcSumThread;
thread->start();	// 開啓線程
thread->wait();		// 等待線程結束

運行結果:
Created Thread Success, Id is 22200
Current Thread ID is 22200, Result is 5050

函數 start() 表示開啓線程(激活線程爲可執行狀態)
函數 wait() 表示阻塞等待線程退出(同 std::thread 的 join函數)


那麼這個 CThread 到底時怎麼實現的呢?
下面是 CThread 的完整實現:
頭文件定義:

#ifndef CTHREAD_H
#define CTHREAD_H

#include <Windows.h>

class CThread
{
public:
	CThread();
	~CThread();

	// 線程入口函數
	virtual void run(void) = 0;

	// 啓動線程
	void start(void);

	// 等待線程函數
	void wait(void);

private:
	static DWORD WINAPI threadProc(LPVOID lpParameters);
	// 創建線程
	void create(void);

	// 線程ID
	DWORD m_nThreadId = 0;
	// 判斷線程是否創建成功
	bool m_isCreatedSuccess = true;
	// 線程句柄
	HANDLE m_threadHandle = nullptr;
};
#endif

源文件:

#include "CThread.h"
#include <iostream>

CThread::CThread()
{
	create();
}

CThread::~CThread()
{

}

void CThread::create(void)
{
	// 創建線程
	HANDLE handle = ::CreateThread(nullptr, 0, CThread::threadProc, this, CREATE_SUSPENDED, &m_nThreadId);

	// 判斷是否創建成功
	if (handle)
	{
		m_isCreatedSuccess = true;
		std::cout << "Created Thread Success, Id is " << m_nThreadId << std::endl;
	}
	else
	{
		std::cout << "Created Thread Failed!!!" << std::endl;
		m_isCreatedSuccess = false;
	}

	m_threadHandle = handle;
}

// 啓動線程
void CThread::start(void)
{
	if (!m_isCreatedSuccess)
		return;

	// 啓動線程
	::ResumeThread(m_threadHandle);
}

// 等待線程函數
void CThread::wait(void)
{
	if (!m_isCreatedSuccess)
		return;

	::WaitForSingleObject(m_threadHandle, INFINITE);
}

DWORD WINAPI CThread::threadProc(LPVOID lpParameters)
{
	CThread* thisPointer = (CThread*)lpParameters;

	// 判斷線程是否創建成功
	if (!thisPointer->m_isCreatedSuccess)
		return 1;

	// 執行自定義入口函數
	thisPointer->run();
	return 0;
}

本質上是使用了一個靜態函數作爲線程的入口函數,將 this 指針作爲函數的參數傳入。如果不是靜態函數,c++本質上會把非靜態函數默認傳遞一個 this 指針作爲參數,不符合線程入口函數的函數指針類型定義,因此此處必須爲靜態函數。

這裏使用參數 CREATE_SUSPENDED 表示,表示創建線程後不立即執行,掛起該線程。

  • start() 函數,啓動線程;使用函數 ResumeThread() 表示將線程從掛起狀態變爲激活狀態,操作系統有一個線程掛起參數,當該參數爲0時,線程變爲激活狀態。使用函數 SuspendThread() 是將該參數+1,使用函數 ResumeThread() 是將該參數-1 。
  • threadProc() ,線程入口函數,將參數轉爲 this ,然後調用虛函數 run()
  • wait() 函數,阻塞等待線程執行完成。使用 WaitForSingleObject() 這個Windows API 實現。

作者:douzhq
個人博客:www.douzhq.cn
文章同步(可下載完整代碼): http://www.douzhq.cn/thread_cthread/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章