1. 线程池的定义及其原理
线程池:一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件,则线程池将插入另一个辅助线程来使所处理器保持繁忙。如果所线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
简而言之,线程池就是:管理一个任务队列,一个线程队列,然后每次取一个任务分配给一个线程去做,循环往复
2. 实现线程池要做什么
1. 一个管理线程,负责增加或者减少线程,管理线程池中工作线程的数量
2. 诸多工作线程
3. 任务队列
3. 通过IO完成端口实现线程池
IO完成端口在实现线程池中的主要作用是:该线程池实现中的IO完成端口为异步的不关联文件的完全IO端口。通过IO完成端口可以完成任务队列的管理以及任务数据到多线程的数据传递。
3.1线程池工作原理如下:
3.2代码实现
ThreadPool.h
/**************************************************************************
* Copyright huashuolin001
* FileName: ThreadPool.h
* Description: 线程池+IOCP队列
* Author: huashuolin001
* Date: 09/07/2020
* Modification History:
* <version> <time> <author> <desc>
* 1.0 09/07/2020 huashuolin001 创建
**************************************************************************/
#pragma once
#include <Windows.h>
//数据基类
class IWorkData
{
public:
IWorkData(){}
virtual ~IWorkData(){}
};
//任务基类
class IWork
{
public:
IWork(){}
virtual ~IWork(){}
virtual void ProcessJob(IWorkData* pWorkData)=0;
};
//线程池
class ThreadPool
{
//线程信息
typedef struct THREADINFO
{
THREADINFO()
{
hThreadHandle = NULL;
dwThreadID = 0;
bIsBusy = false;
bIsQuit = false;
}
HANDLE hThreadHandle;//线程句柄
unsigned dwThreadID;//线程ID
volatile bool bIsBusy;//是否工作中的状态
volatile bool bIsQuit;//是否退出
}*LPTHREADINFO;
public:
static ThreadPool* Instance();
enum EReturnValue
{
MANAGERPROC_RETURN_VALUE = 10001,
WORKERPROC_RETURN_VALUE = 10002
};
enum EThreadStatus
{
BUSY,//繁忙
NORMAL,//正常
IDLE//空闲
};
bool Start(WORD wStatic,WORD wMax);
void Stop(void);
int GetCurThreadCount();
void ProcessJob(IWork* pWorker,IWorkData* pWorkData) const;
protected:
static unsigned __stdcall ManagerProc(void* pThread);
static unsigned __stdcall WorkerProc(void* pThread);
LPTHREADINFO m_pThreadInfo;
volatile WORD m_wStaticThreadNum;
volatile WORD m_wMaxThreadNum;
volatile bool m_bQuitManager;
DWORD m_dwMSeconds;
HANDLE m_hManagerIO;
HANDLE m_hWorkerIO;
HANDLE m_hManagerThread;
CRITICAL_SECTION m_csLock;
int m_nCurThrdCount;
private:
ThreadPool::EThreadStatus GetWorkThreadStatus();
void AddThread(void);
void DelThread(void);
int GetThreadbyID(DWORD dwID);
ThreadPool(void);
~ThreadPool(void);
};
ThreadPool.cpp
/**************************************************************************
* Copyright huashuolin001
* FileName: ThreadPool.cpp
* Description: 线程池+IOCP队列
* Author: huashuolin001
* Date: 09/07/2020
* Modification History:
* <version> <time> <author> <desc>
* 1.0 09/07/2020 huashuolin001 创建
**************************************************************************/
#include "StdAfx.h"
#include "ThreadPool.h"
#include "process.h"
#include <new>
ThreadPool::ThreadPool()
{
m_hManagerIO = NULL;
m_hWorkerIO = NULL;
m_hManagerThread= NULL;
m_pThreadInfo = NULL;
m_dwMSeconds = 200;
m_bQuitManager = false;
::InitializeCriticalSection(&m_csLock);
}
ThreadPool::~ThreadPool()
{
//关闭IO
if(m_hManagerIO)
{
::CloseHandle(m_hManagerIO);
}
if(m_hWorkerIO)
{
::CloseHandle(m_hWorkerIO);
}
if(m_pThreadInfo)
{
delete[] m_pThreadInfo;
}
::DeleteCriticalSection(&m_csLock);
}
ThreadPool* ThreadPool::Instance()
{
static ThreadPool g_singletonObj;
return &g_singletonObj;
}
bool ThreadPool::Start(WORD wStatic,WORD wMax)
{
//AMS_INFO("启动线程池,初始个数%d,最大个数%d\r\n",wStatic,wMax);//lg_test
if(!(wStatic && wMax))
{
return false;
}
m_wStaticThreadNum = wStatic;
m_wMaxThreadNum = wMax;
m_nCurThrdCount = wStatic;
::EnterCriticalSection(&m_csLock);
//创建工作线程数据
if(m_pThreadInfo)
{
delete [] m_pThreadInfo;
m_pThreadInfo = NULL;
}
m_pThreadInfo = new (std::nothrow) THREADINFO[wMax]();
if (m_pThreadInfo == NULL)
{
//AMS_INFO("New memory for m_pThreadInfo failed\r\n");//lg_test
return false;
}
//创建异步的不关联文件的完全IO端口
if(m_hManagerIO)
{
::CloseHandle(m_hManagerIO);
m_hManagerIO = NULL;
}
m_hManagerIO = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if(m_hManagerIO == NULL)
{
return false;
}
if(m_hWorkerIO)
{
::CloseHandle(m_hWorkerIO);
m_hManagerIO = NULL;
}
m_hWorkerIO = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if(m_hWorkerIO == NULL)
{
return false;
}
//创建管理线程
m_bQuitManager = false;
if(m_hManagerThread)
{
::TerminateThread(m_hManagerThread,0);
m_hManagerThread = NULL;
}
unsigned ManagerThreadID;
m_hManagerThread = (HANDLE)_beginthreadex(NULL,0,ManagerProc,this,0,&ManagerThreadID);
if(m_hManagerThread == NULL)
{
return false;
}
//创建工作线程
for(WORD i = 0;i < wStatic;++i)
{
m_pThreadInfo[i].hThreadHandle = (HANDLE)_beginthreadex(NULL,0,WorkerProc,this,0,&m_pThreadInfo[i].dwThreadID);
}
::LeaveCriticalSection(&m_csLock);
return true;
}
void ThreadPool::Stop(void)
{
::EnterCriticalSection(&m_csLock);
//判断并关闭管理线程
DWORD dwRes;
if (m_pThreadInfo)
{
//关闭所有工作线程
for(int i= 0;i < m_wMaxThreadNum;i++)
{
if(m_pThreadInfo[i].dwThreadID == 0)
{
continue;
}
m_pThreadInfo[i].bIsQuit = true;
while (true)
{
//等待工作线程全部执行完
::GetExitCodeThread(m_pThreadInfo[i].hThreadHandle,&dwRes);
if(dwRes == ThreadPool::WORKERPROC_RETURN_VALUE)
{
break;
}
}
}
}
//向管理线程发送关闭线程消息
m_bQuitManager = true;
for(int i= 0;i < 10;i++)
{
::GetExitCodeThread(m_hManagerThread,&dwRes);
if(dwRes == ThreadPool::MANAGERPROC_RETURN_VALUE)
{
break;
}
if(i == 9)
{
//关闭线程
::TerminateThread(m_hManagerThread,0);
}
else
{
::Sleep(1000);
}
}
//关闭IO
::CloseHandle(m_hManagerIO);
m_hManagerIO = NULL;
//删除所有待处理的数据
unsigned long pN1,pN2;
OVERLAPPED* pOverLapped;
while(::GetQueuedCompletionStatus(m_hWorkerIO,&pN1,&pN2,&pOverLapped,0))
{
//AMS_INFO("退出线程池前仍有未执行完的任务\r\n");lg_test
//IWork* pWork = reinterpret_cast<IWork*>(pN1);
IWorkData* pWorkData = reinterpret_cast<IWorkData*>(pN2);
if (pWorkData)
{
delete pWorkData;
pWorkData = NULL;
}
}
//删除线程结构
if(m_pThreadInfo)
{
delete []m_pThreadInfo;
m_pThreadInfo = NULL;
}
//关闭IO
::CloseHandle(m_hWorkerIO);
m_hWorkerIO = NULL;
::LeaveCriticalSection(&m_csLock);
}
void ThreadPool::ProcessJob(IWork* pWorker,IWorkData* pWorkData) const
{
::PostQueuedCompletionStatus(m_hWorkerIO,
reinterpret_cast<DWORD>(pWorker),
reinterpret_cast<DWORD>(pWorkData),
NULL);
}
unsigned __stdcall ThreadPool::ManagerProc(void* pThread)
{
unsigned long pN1, pN2;
OVERLAPPED* pOverLapped;
ThreadPool* pServer = reinterpret_cast<ThreadPool*>(pThread);
while(!pServer->m_bQuitManager)
{
if(::GetQueuedCompletionStatus(pServer->m_hManagerIO,&pN1,&pN2,&pOverLapped,pServer->m_dwMSeconds) == TRUE)
{
if(pOverLapped == (OVERLAPPED*)0xFFFFFFFF)
{
//收到退出码
break;
}
}
else
{
//超时,判断工作线程状态
EThreadStatus stat = pServer->GetWorkThreadStatus();
if(stat == ThreadPool::BUSY)
{
pServer->AddThread();
}
else if(stat == ThreadPool::IDLE)
{
pServer->DelThread();
}
}
}
_endthreadex(ThreadPool::MANAGERPROC_RETURN_VALUE);
return ThreadPool::MANAGERPROC_RETURN_VALUE;
}
unsigned __stdcall ThreadPool::WorkerProc(void* pThread)
{
//STRY;lg_test
unsigned long pN1, pN2;
OVERLAPPED* pOverLapped;
ThreadPool* pServer = reinterpret_cast<ThreadPool*>(pThread);
DWORD threadID = ::GetCurrentThreadId();
int nSeq = pServer->GetThreadbyID(threadID);
if(nSeq < 0)
{
return 0;
}
while(!pServer->m_pThreadInfo[nSeq].bIsQuit)
{
try
{
if(::GetQueuedCompletionStatus(pServer->m_hWorkerIO,&pN1,&pN2,&pOverLapped,pServer->m_dwMSeconds))
{
IWork* pWork = reinterpret_cast<IWork*>(pN1);
IWorkData* pWorkData = reinterpret_cast<IWorkData*>(pN2);
//在工作之前将状态设置为Busy
pServer->m_pThreadInfo[nSeq].bIsBusy = true;
//工作处理过程
if (pWork)
{
pWork->ProcessJob(pWorkData);
}
//析构工作数据
if (pWorkData)
{
delete pWorkData;
}
//在工作后将状态设置为非Busy
pServer->m_pThreadInfo[nSeq].bIsBusy = false;
}
}
catch (...)
{
//AMS_INFO("WorkerProc has problem, threadID = %d\r\n", threadID);//lg_test
}
}
//退出之前将线程ID设置为0
pServer->m_pThreadInfo[nSeq].dwThreadID = 0;
_endthreadex(ThreadPool::WORKERPROC_RETURN_VALUE);
return ThreadPool::WORKERPROC_RETURN_VALUE;
//SCATCH;lg_test
return 0;
}
ThreadPool::EThreadStatus ThreadPool::GetWorkThreadStatus()
{
float fAll = 0.0,fRun = 0.0;
if (m_pThreadInfo)
{
for(WORD wi = 0; wi < m_wMaxThreadNum; ++wi)
{
if(m_pThreadInfo[wi].dwThreadID)
{
fAll++;
if(m_pThreadInfo[wi].bIsBusy)
{
fRun++;
}
}
}
}
if(fAll == 0)
{
return ThreadPool::IDLE;
}
if(fRun / (1.0 * fAll) > 0.8)
{
return ThreadPool::BUSY;
}
if(fRun / (1.0 * fAll) < 0.2)
{
return ThreadPool::IDLE;
}
return ThreadPool::NORMAL;
}
void ThreadPool::AddThread(void)
{
if (m_pThreadInfo)
{
for(WORD wi = m_wStaticThreadNum; wi < m_wMaxThreadNum; ++wi)
{
if(m_pThreadInfo[wi].dwThreadID == 0 && m_nCurThrdCount <= m_wMaxThreadNum)
{
m_pThreadInfo[wi].bIsBusy = false;
m_pThreadInfo[wi].bIsQuit = false;
m_pThreadInfo[wi].hThreadHandle = (HANDLE)_beginthreadex(NULL,0,WorkerProc,this,0,&m_pThreadInfo[wi].dwThreadID);
m_nCurThrdCount++;
//AMS_INFO("第 %d 个线程创建 ThreadId[%d] = %d\r\n",m_nCurThrdCount,wi,m_pThreadInfo[wi].dwThreadID);//lg_test
break;
}
}
}
}
void ThreadPool::DelThread(void)
{
if (m_pThreadInfo)
{
for(WORD wi = m_wMaxThreadNum; wi > m_wStaticThreadNum; --wi)
{
if(m_pThreadInfo[wi-1].dwThreadID != 0)
{
m_pThreadInfo[wi-1].bIsQuit = true;
::Sleep(m_dwMSeconds);
break;
}
}
}
}
int ThreadPool::GetThreadbyID(DWORD dwID)
{
if (m_pThreadInfo)
{
for(WORD wi = 0;wi < m_wMaxThreadNum; wi++)
{
if(m_pThreadInfo[wi].dwThreadID == dwID)
{
return wi;
}
}
}
return -1;
}
int ThreadPool::GetCurThreadCount()
{
return m_nCurThrdCount;
}
MyDataDeal.h
#ifndef _MY_DATA_DEAL_CPP
#define _MY_DATA_DEAL_CPP
#include "ThreadPool.h"
#include <string>
typedef struct tagPersonInfo : public IWorkData
{
std::string strName;
int iAge;
tagPersonInfo()
{
strName = "";
int iAge = 0;
}
tagPersonInfo &operator = (const tagPersonInfo& Other)
{
if (this == &Other)
{
return *this;
}
strName = Other.strName;
iAge = Other.iAge;
return *this;
}
}PersonInfo;
class CMyDataDeal : public IWork
{
public:
CMyDataDeal()
{
};
virtual ~CMyDataDeal()
{
};
//处理数据
void ProcessData(PersonInfo* pPersonInfo);
private:
void ProcessJob(IWorkData* pWorkData);
};
#endif
MyDataDeal.cpp
#include "MyDataDeal.h"
#include <iostream>
void CMyDataDeal::ProcessJob( IWorkData* pWorkData )
{
PersonInfo* pPersonInfo = (PersonInfo*) pWorkData;
std::cout<<"姓名:"<<pPersonInfo->strName<<std::endl;
std::cout<<"年龄:"<<pPersonInfo->iAge<<std::endl;
}
void CMyDataDeal::ProcessData( PersonInfo* pPersonInfo )
{
ThreadPool::Instance()->ProcessJob(this, pPersonInfo);
}
main.cpp
// ThreadPool_Test_Com.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "MyDataDeal.h"
#define MAX_THREAD 256
int _tmain(int argc, _TCHAR* argv[])
{
ThreadPool::Instance()->Start(10, MAX_THREAD);
CMyDataDeal MyDataDeal;
PersonInfo* pPersonInfo = new(std::nothrow) PersonInfo;
pPersonInfo->strName = "程序员A";
pPersonInfo->iAge = 27;
MyDataDeal.ProcessData(pPersonInfo);
//ThreadPool::Instance()->GetCurThreadCount();
ThreadPool::Instance()->Stop();
if (NULL != pPersonInfo)
{
delete pPersonInfo;
pPersonInfo = NULL;
}
system("pause");
return 0;
}