思路:創建線程池時啓動固定個數線程,線程函數中循環監聽任務隊列,取出任務並執行,在此處我將指針函數作爲任務傳遞入口,存在弊端就是任務處理函數簽名固定了,靈活性低。當然,也可以將任務進行封裝,使用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;
}
執行結果: