在计算机程序中,线程是一种很重要的资源,使用的恰当可以极大的提高程序的效率,也就是多线程的使用,但是多线程会让应用程序变得异常复杂,会占用大量的系统资源。就像QQ表情一样,每一个QQ表情的闪动都需要构建一个线程,如果用户使用了大量的表情(GIF),将会有多少个线程在运行,系统的性能将大大减少,甚至导致死机。在这种情况下,多线程变得不太合适了,那么什么机制适用于这种情况下呢,这就是线程池。
通常情况下,应用程序中采用异步调用函数的形式来实现多任务,在windows中,系统提供了QueueUserWorkItem函数实现异步调用,这个函数相当于在线程池中建立多个用户工作项目,跟普通线程机制一样,线程池也有线程的同步等机制。查MSDN,可看到QueueUserWorkItem函数语法如下:
BOOL WINAPI QueueUserWorkItem(
__in LPTHREAD_START_ROUTINE Function,
__in_opt PVOID Context,
__in ULONG Flags);
Function就是用户定义的函数,context是P指针,也是Function的参数,Flags表示一组标志值,作用可通过查MSDN看到,这里就不在叙述。
下面实现了一个简单的线程池程序,没有什么大的功能,可以看到线程池的用法。
#include <iostream>
#include <assert.h>
#include <Windows.h>
#include <string>
using namespace std;
DWORD WINAPI TestThreadPool1(PVOID pContext);
DWORD WINAPI TestThreadPool2(PVOID pContext);
DWORD WINAPI TestThreadPool3(PVOID pContext);
CRITICAL_SECTION g_cs;
int main(int argc, char * argv[])
{
QueueUserWorkItem(TestThreadPool1, L"Hello World", WT_EXECUTEDEFAULT);
QueueUserWorkItem(TestThreadPool2, L"Hello World", WT_EXECUTEDEFAULT);
QueueUserWorkItem(TestThreadPool3, L"Hello World", WT_EXECUTEDEFAULT);
getchar();
return 0;
}
DWORD WINAPI TestThreadPool1(PVOID pContext)
{
for(int i=0;i<=100;i++)
{
cout<<"One Thread is : "<<i<<endl;
}
return 0;
}
DWORD WINAPI TestThreadPool2(PVOID pContext)
{
for(int i=0;i<=100;i++)
{
cout<<"Two Thread is : "<<i<<endl;
}
return 0;
}
DWORD WINAPI TestThreadPool3(PVOID pContext)
{
for(int i=0;i<=100;i++)
{
cout<<"Three Thread is : "<<i<<endl;
}
return 0;
}
#include <Windows.h>
#include <stdio.h>
#include <functional>
using namespace std::placeholders;
class Arbitrary {
public:
bool UsefulPublicFunction(int uParameter);
protected:
private:
typedef std::function<void (void)> CallbackType;
static DWORD WINAPI ProcessWorkItem(void* pVoid);
void PrivateWorkItem1(int arg1, int arg2);
void PrivateWorkItem2(char * arg1);
};
void Arbitrary::PrivateWorkItem1(int arg1, int arg2)
{
printf("Numbers are %u %u\n", arg1, arg2);
return;
}
void Arbitrary::PrivateWorkItem2(char * arg1)
{
printf("String is %s\n", arg1);
return;
}
DWORD WINAPI Arbitrary::ProcessWorkItem(void* pVoid)
{
CallbackType * callback = static_cast<CallbackType *>(pVoid);
(*callback)();
delete callback;
return 0;
}
bool Arbitrary::UsefulPublicFunction(int param1)
{
QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem1, this, param1, 7)), 0);
QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem2, this, (char *)"This is my string")), 0);
Sleep(1000);
return true;
}
int main(int argc, char ** argv)
{
Arbitrary x;
x.UsefulPublicFunction(5);
return 0;
}
//threadpool:
#ifndef __ZGM_THREAD_POOL_H__
#define __ZGM_THREAD_POOL_H__
#pragma once
#include <list>
#include <windows.h>
namespace ZgmPool
{
struct ZgmTask//线程任务基类,所有的线程任务如果需要使用本线程池,则需要申明本类的子类,并重载runFunc方法。
{
ZgmTask(void*p) :param(p),lockCount(0) { }
static int run(void*p)//本线程函数传入QueueUserWorkItem中,包装了runFunc函数,以便统计当前线程运行个数
{
ZgmTask*task = static_cast<ZgmTask*>(p);
::InterlockedIncrement(task->lockCount);
int ret = task->runFunc(task->param);
::InterlockedDecrement(task->lockCount);
delete task;//退出时需要删除该任务对象。
return ret;
}
void setCount(long*count) { lockCount = count;}
virtual int runFunc(void*p)=0;
virtual ~ZgmTask() { }
private:
void*param;
long *lockCount;
};
class ZgmThreadPool
{
class ZgmLock//锁对象,用于互斥变量方便的锁定/解锁。
{
HANDLE handle;
ZgmLock(const ZgmLock&);
ZgmLock& operator=(const ZgmLock&);
public:
explicit ZgmLock(HANDLE hMutex) : handle(hMutex){ ::WaitForSingleObject(handle,INFINITE); }
~ZgmLock(){ ::ReleaseMutex(handle); }
};
HANDLE pthread;
HANDLE hMutex;
long lockCount;
long maxThreads;
bool bExit;
std::list<ZgmTask*> tasks;
public:
ZgmThreadPool(long mThreads) : maxThreads(mThreads),lockCount(0)
{
bExit = false;
hMutex = ::CreateMutex(0,false,0);
pthread = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ZgmThreadPool::run, this, 0, 0);
}
void AddTask(ZgmTask*task)
{
ZgmLock l(hMutex);//获得线程锁
task->setCount(&lockCount);//添加任务之前需要将统计的线程个数传入具体task类中,以便该task本身计算自己线程是否退出。
tasks.push_back(task);
}
~ZgmThreadPool()
{
bExit = true;
CloseHandle(hMutex);
CloseHandle(pthread);
}
// 线程控制函数,用于线程池控制,主要目的是为了不间断的查看task列表中是否有任务,
// 有并且还不到线程最大值,则开启一个线程任务,否则挂起。
static int run(void*p)
{
ZgmThreadPool*pool = static_cast<ZgmThreadPool*>(p);
while( !pool->bExit )
{
if( ( pool->lockCount < pool->maxThreads ) && pool->tasks.size())
{
ZgmLock l(pool->hMutex);//获得线程锁
::QueueUserWorkItem((LPTHREAD_START_ROUTINE)ZgmTask::run,pool->tasks.back(),1);//开启线程任务
pool->tasks.pop_back();
}
//挂起
Sleep(0);
}
return 0;
}
};
}
#endif // __ZGM_THREAD_POOL_H__