线程池可以看为一个预留出的延时关闭的线程的集合。通过创建睡眠这些线程,随时唤醒,并保证线程池大小与运行所需类似,随时关闭,并维持线程的动态平衡。
线程池作用
1.降低资源消耗,以复用线程方法,减少线程关闭,减少系统资源损耗。
2.提升响应速度,减少线程创建。
3.提高线程管理性。
基本框架
创建所需线程
线程实现的函数
投递任务
使用后销毁
这里我使用QT来操作
以下放置在一个类中,这个类就是我们的线程池class threadpool。
我们无需实现创建线程的函数,所以第一步需要创建一个线程池的创建部分,用以循环放置创建函数。
创建线程池
创建线程量
计算密集型
需要非常多的CPU计算资源。
线程数=CPU核数+1
IO密集型
有大量IO操作,进行等待,可增加线程数。
线程数=CPU核数/(1-阻塞系数)
阻塞系数取0.8~0.9
这些是通常情况下的,也要根据具体情况来考虑。
关于线程创建的函数
例:HANDLE hThread =CreateThread(0,0,&threadProc,this,0,0);
返回值类型为句柄:HANDLE
右侧函数需六个参数,在windows官网能查到更明确的解释。
于是我们添加循环,
我们需要考虑创建空间的上下限,各为多少,以及怎么关联起这些线程。
按需求定义线程池的大小,可通过参数实现。关联方法可以用STL容器,这里我们用List举例,通过List的定义方法:
list<HANDLE> m_lstThread;
注意要引用std命名空间中的<list>头文件。
同过链表方法链接就可以,例(添加至末尾):
m_lstThread.push_back(hThread);
函数使用方法查阅很容易,不做赘述。
线程函数
例:DWORD threadpool::threadProc(LPVOID lpvoid)
线程池的线程函数的作用是遍历整个线程池并处理运行任务。
接下来是比较必要的一部分,处理线程同步。
在函数实现时,已创建的线程都会从线程函数中运行,若多个线程同时进行遍历,指向线程的参数就十分容易混乱,尤其是线程处理任务时,同时进行的线程已经多次遍历,任务却没有成功输出,出现BUG。
而处理这种线程同步有两种方式,代码段或内核对象,可以看作一个线程版的if函数,运行后调整信号使其他线程无法运行,直到条件达成,信号转化,有信号和无信号按两种操作手段,函数不需要实现,可在windows官方搜索。
此程序使用的是内核对象中的互斥量,CreateMutex()创建,同时还有等待信号的通用函数Waitforsingleobject(),内核对象还有事件和信号量,这里没有使用。
接下来线程函数按照自己的逻辑和习惯调整遍历顺序和实现功能就可以了。
接口
为方便不同参数使用同一线程池,避免重复构造新函数或新线程池,所以用接口类来链接新函数,子类公共继承接口类,直接用接口操作。
任务队列
实现了有序运行,我们也要考虑有序输入,创造一个投递任务的任务队列,由于无需时刻保持,可以直接自定义函数实现。
实现线程动态平衡
线程创建后可能会赘余或不足,需要我们按情况来调整线程的总量,来节省运算消耗。增加线程可以用创建的类似方式,又因为需要保持程序运行时始终存活,需要新定义一个线程用来操控线程池内线程数。方法如上,线程函数主要用来控制线程池。
线程池释放
无需时刻运行,使用函数在尾部释放,可用list函数方法。
注:关闭所有句柄。
附(代码)
头文件
名称:threadpool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <list>
#include <windows.h>
#include <queue>
#define MAXITASKNUM 10000
class Itask
{
public:
Itask(){};
virtual ~Itask(){};
virtual void run() = 0;
};
class threadpool
{
public:
threadpool();
virtual ~threadpool();
public:
bool createThreadPool(long lMinthreadNum,long lMaxThreadNum);
void destroyThreadpool();
static DWORD WINAPI threadProc(LPVOID lpvoid);
bool push(Itask*);
static DWORD WINAPI threadManager(LPVOID lpvoid);
private:
std::list<HANDLE> m_lstThread;
std::queue<Itask*> m_qItask;
HANDLE m_hSemaphore;
HANDLE m_hMutex;
bool m_bFlagQuit;
long m_lCreateThreadNum;
long m_lRunThreadNum;
long m_lMaxThreadNum;
long m_lMinThreadNum;
long m_exitcode;
};
#endif // THREADPOOL_H
源文件
名称:threadpool.cpp
#include "threadpool.h"
Itask *pItask;
threadpool::threadpool()
{
m_bFlagQuit =true;
m_lCreateThreadNum =0;
m_lRunThreadNum =0;
m_lMaxThreadNum =0;
m_lMinThreadNum =0;
m_exitcode =0;
m_hMutex =CreateMutex(0,0,0);
}
threadpool::~threadpool()
{
}
bool threadpool::createThreadPool(long lMinthreadNum, long lMaxThreadNum)
{
if(lMinthreadNum <= 0 ||lMaxThreadNum <lMinthreadNum)
return false;
HANDLE hThread;
m_hSemaphore = CreateSemaphore(0,0,MAXITASKNUM,0);
for(long i = 0;i<lMinthreadNum;i++)
{
hThread =CreateThread(0,0,&threadProc,this,0,0);
if(hThread)
m_lstThread.push_back(hThread);
}
hThread =CreateThread(0,0,&threadManager,this,0,0);
if(hThread)
m_lstThread.push_back(hThread);
m_lMaxThreadNum = lMaxThreadNum;
m_lCreateThreadNum = lMinthreadNum;
m_lMinThreadNum =lMinthreadNum;
return true;
}
bool threadpool::push(Itask *pItask)
{
if(!pItask)
return false;
WaitForSingleObject(m_hMutex,INFINITE);
m_qItask.push(pItask);
ReleaseMutex(m_hMutex);
if(m_lRunThreadNum == m_lCreateThreadNum && m_lCreateThreadNum < m_lMaxThreadNum)
{
HANDLE hThread = CreateThread(0,0,&threadProc,this,0,0);
if(hThread)
m_lstThread.push_back(hThread);
++m_lCreateThreadNum;
}
ReleaseSemaphore(m_hSemaphore,1,0);
return true;
}
DWORD threadpool::threadManager(LPVOID lpvoid)
{
threadpool *pthis =(threadpool*)lpvoid;
long lRunThreadNum;
long lCreateThreadNum;
while(pthis->m_bFlagQuit)
{
//CreateWaitableTimer()
Sleep(5000);
lRunThreadNum =pthis->m_lRunThreadNum;
lCreateThreadNum =pthis->m_lMinThreadNum;
if(lCreateThreadNum -lRunThreadNum >pthis->m_lMinThreadNum)
{
pthis->m_exitcode = pthis->m_lMinThreadNum;
ReleaseSemaphore(pthis->m_hSemaphore,pthis->m_lMinThreadNum,0);
}
}
return 0;
}
void threadpool::destroyThreadpool()
{
m_bFlagQuit =false;
auto ite = m_lstThread.begin();
while(ite != m_lstThread.end());
{
TerminateThread(*ite,-1);
CloseHandle(*ite);
*ite = NULL;
++ite;
}
m_lstThread.clear();
if(m_hSemaphore)
{
CloseHandle(m_hSemaphore);
m_hSemaphore =0;
}
if(m_hMutex)
{
CloseHandle(m_hMutex);
m_hMutex =0;
}
Itask *pItask =0;
while(m_qItask.empty())
{
pItask =m_qItask.front();
m_qItask.pop();
delete pItask;
pItask =0;
}
}
DWORD threadpool::threadProc(LPVOID lpvoid)
{
threadpool *pthis = (threadpool*)lpvoid;
Itask *pItask =NULL;
while(pthis->m_bFlagQuit)
{
WaitForSingleObject(pthis->m_hSemaphore,INFINITE);
InterlockedIncrement(&pthis->m_lRunThreadNum);
if(!pthis->m_qItask.empty())
{
WaitForSingleObject(pthis->m_hMutex,INFINITE);
if(!pthis->m_exitcode)
{
--pthis->m_exitcode;
ReleaseMutex(pthis->m_hMutex);
InterlockedDecrementRelease(&pthis->m_lRunThreadNum);
break;
}
if(pthis->m_qItask.empty())
{
ReleaseMutex(pthis->m_hMutex);
break;
}
pItask = pthis->m_qItask.front();
pthis->m_qItask.pop();
ReleaseMutex(pthis->m_hMutex);
if(pItask)
pItask->run();
delete pItask;
pItask =0;
}
InterlockedDecrement(&pthis->m_lRunThreadNum);
}
return 0;
}
主函数
#include <QCoreApplication>
#include "threadpool.h"
#include <iostream>
using namespace std;
class AddItask:public Itask
{
public:
AddItask(int a,int b)
{
m_a =a;
m_b =b;
}
void run()
{
cout<<m_a<<"+"<<m_b<<"="<<m_a+m_b<<endl;
}
private:
int m_a;
int m_b;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
threadpool tp;
tp.createThreadPool(1,1000);
for(int i =0;i <=100000;i++)
{
Itask *p =new AddItask(i+1,4);
tp.push(p);
}
return a.exec();
}