C++線程池簡單實現(windows)

思路:創建線程池時啓動固定個數線程,線程函數中循環監聽任務隊列,取出任務並執行,在此處我將指針函數作爲任務傳遞入口,存在弊端就是任務處理函數簽名固定了,靈活性低。當然,也可以將任務進行封裝,使用C++的多態特性來完成不同類型的任務。

關鍵要點:
1、使用queue作爲消息隊列的載體
queue 的基本操作有:
入隊,如例:q.push(x); 將x 接到隊列的末端。
出隊,如例:q.pop(); 彈出隊列的第一個元素,注意,並不會返回被彈出元素的值。
訪問隊首元素,如例:q.front(),即最早被壓入隊列的元素。
訪問隊尾元素,如例:q.back(),即最後被壓入隊列的元素。
判斷隊列空,如例:q.empty(),當隊列空時,返回true。
2、typedef void (*Task)();//定義任務指針函數
3、Windows下工作線程函數

extern "C"
{
	DWORD WINAPI WorkTask(LPVOID* param);//線程函數
}

4、mutex 互斥變量,用作同步

CThreadPool類:
.h

#ifndef _THREADPOOR_H_
#define _THREADPOOR_H_

#include <queue>
#include <mutex>
#include <vector>
#include <wtypes.h>

/*
queue 的基本操作有:
入隊,如例:q.push(x); 將x 接到隊列的末端。
出隊,如例:q.pop(); 彈出隊列的第一個元素,注意,並不會返回被彈出元素的值。
訪問隊首元素,如例:q.front(),即最早被壓入隊列的元素。
訪問隊尾元素,如例:q.back(),即最後被壓入隊列的元素。
判斷隊列空,如例:q.empty(),當隊列空時,返回true。
*/

using namespace std;
typedef void (*Task)();//定義任務指針函數
extern "C"
{
	DWORD WINAPI WorkTask(LPVOID* param);//線程函數
}

//線程池
class CThreadpool
{
public:
	CThreadpool();
	~CThreadpool();
public:
	void InitialThreadPool();//創建線程
	void AddTaskToQueue(const Task& task);//添加任務入隊列
	void SetMaxThreadsNum(int nMaxNum);//設置線程數
	//void SetMinThreadsNum(int nMinNum);
	void ExitThreadPool();//退出線程池處理
	queue<Task> m_qTasks;//任務隊列
	mutex m_mMutex;//互斥變量
	bool m_bIsStop;//停止線程
private:
	int m_nMaxNum;//最大線程數
	//int m_nMinNum;//最小線程數
	vector<HANDLE> m_vecThreadHandles;//存放線程句柄
};

#endif // !_THREADPOOR_H_

.cpp

#include "stdafx.h"
#include "Threadpool.h"
#include <stdio.h>

CThreadpool::CThreadpool()
{
	m_nMaxNum = 5;//初始化線程數量
	m_bIsStop = false;
	m_vecThreadHandles.resize(m_nMaxNum);
}

CThreadpool::~CThreadpool()
{
}

void CThreadpool::SetMaxThreadsNum(int nMaxNum)
{
	m_nMaxNum = nMaxNum;
}

//void CThreadpool::SetMinThreadsNum(int nMinNum)
//{
//	m_nMinNum = nMinNum;
//}

//線程函數
DWORD WINAPI WorkTask(LPVOID* param)
{
	CThreadpool* pool = (CThreadpool*)param;
	while (!pool->m_bIsStop)
	{
		Sleep(1);
		pool->m_mMutex.lock();
		if (pool->m_qTasks.size() <= 0)//隊列爲空,繼續執行循環
		{
			//printf("隊列爲空,等待任務...\n");
			pool->m_mMutex.unlock();
			continue;
		}

		Task task = pool->m_qTasks.front();//取出第一個任務
		pool->m_qTasks.pop();//將第一個任務彈出隊列
		pool->m_mMutex.unlock();

		(*task)();//執行任務函數
	}

	return NULL;
}

//創建線程
void CThreadpool::InitialThreadPool()
{
	for (int i = 0; i < m_nMaxNum; ++i)
	{
		m_vecThreadHandles[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkTask, (LPVOID*)this, 0, NULL);
	}
}

//任務入隊
void CThreadpool::AddTaskToQueue(const Task& task)
{
	m_mMutex.lock();
	m_qTasks.emplace(task);//將任務加入隊尾
	m_mMutex.unlock();
}

//退出線程池 之前先停掉線程函數中的循環,然後等待線程結束
void CThreadpool::ExitThreadPool()
{
	m_bIsStop = true;
	for (int i = 0; i < (int)m_vecThreadHandles.size();++i)
	{
		WaitForSingleObject(m_vecThreadHandles[i],INFINITE);
	}
}

測試代碼:

// ThreadpoolTest.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include <stdio.h>
#include "Threadpool.h"

void taskTest()
{
	Sleep(5);
	printf("執行任務中,線程ID%u\n",GetCurrentThreadId());
	Sleep(5);
}

void sumTest1()
{
	Sleep(5);
	int a = 33 * 55;
	printf("a=%d,線程ID%u\n", a, GetCurrentThreadId());
}

void taskTest2()
{
	Sleep(5);
	printf("執行任務中2,線程ID%u\n", GetCurrentThreadId());
}

void sumTest3()
{
	Sleep(5);
	int a = 31 * 55;
	printf("a=%d,線程ID%u\n", a, GetCurrentThreadId());
}

int _tmain(int argc, _TCHAR* argv[])
{
	CThreadpool pool;
	pool.SetMaxThreadsNum(3);
	pool.InitialThreadPool();
	pool.AddTaskToQueue(taskTest);
	pool.AddTaskToQueue(sumTest1);
	pool.AddTaskToQueue(taskTest2);
	pool.AddTaskToQueue(sumTest3);
	pool.AddTaskToQueue(sumTest1);

	Sleep(100);
	getchar();
	//system("pause");

	pool.ExitThreadPool();

	return 0;
}

執行結果:
在這裏插入圖片描述

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