#ifndef _ThreadPool_H_
#define _ThreadPool_H_
#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#include <cassert>
#include <vector>
#include <queue>
#include <windows.h>
using namespace std;
class ThreadJob //工作基类
{
public:
//供线程池调用的虚函数
virtual void DoJob(void *pPara) = ;
};
class ThreadPool
{
public:
//dwNum 线程池规模
ThreadPool(DWORD dwNum = ) : _lThreadNum(), _lRunningNum()
{
InitializeCriticalSection(&_csThreadVector);
InitializeCriticalSection(&_csWorkQueue);
_EventComplete = CreateEvent(, false, false, NULL);
_EventEnd = CreateEvent(, true, false, NULL);
_SemaphoreCall = CreateSemaphore(, , 0x7FFFFFFF, NULL);
_SemaphoreDel = CreateSemaphore(, , 0x7FFFFFFF, NULL);
assert(_SemaphoreCall != INVALID_HANDLE_VALUE);
assert(_EventComplete != INVALID_HANDLE_VALUE);
assert(_EventEnd != INVALID_HANDLE_VALUE);
assert(_SemaphoreDel != INVALID_HANDLE_VALUE);
AdjustSize(dwNum <= ? : dwNum);
}
~ThreadPool()
{
DeleteCriticalSection(&_csWorkQueue);
CloseHandle(_EventEnd);
CloseHandle(_EventComplete);
CloseHandle(_SemaphoreCall);
CloseHandle(_SemaphoreDel);
vector<ThreadItem*>::iterator iter;
for(iter = _ThreadVector.begin(); iter != _ThreadVector.end(); iter++)
{
if(*iter)
delete *iter;
}
DeleteCriticalSection(&_csThreadVector);
}
//调整线程池规模
int AdjustSize(int iNum)
{
if(iNum > )
{
ThreadItem *pNew;
EnterCriticalSection(&_csThreadVector);
for(int _i=; _i<iNum; _i++)
{
_ThreadVector.push_back(pNew = new ThreadItem(this));
assert(pNew);
pNew->_Handle = CreateThread(NULL, , DefaultJobProc, pNew, , NULL);
// set priority
SetThreadPriority(pNew->_Handle, THREAD_PRIORITY_BELOW_NORMAL);
assert(pNew->_Handle);
}
LeaveCriticalSection(&_csThreadVector);
}
else
{
iNum *= -;
ReleaseSemaphore(_SemaphoreDel, iNum > _lThreadNum ? _lThreadNum : iNum, NULL);
}
return (int)_lThreadNum;
}
//调用线程池
void Call(void (*pFunc)(void *), void *pPara = NULL)
{
assert(pFunc);
EnterCriticalSection(&_csWorkQueue);
_JobQueue.push(new JobItem(pFunc, pPara));
LeaveCriticalSection(&_csWorkQueue);
ReleaseSemaphore(_SemaphoreCall, , NULL);
}
//调用线程池
inline void Call(ThreadJob * p, void *pPara = NULL)
{
Call(CallProc, new CallProcPara(p, pPara));
}
//结束线程池, 并同步等待
bool EndAndWait(DWORD dwWaitTime = INFINITE)
{
SetEvent(_EventEnd);
return WaitForSingleObject(_EventComplete, dwWaitTime) == WAIT_OBJECT_0;
}
//结束线程池
inline void End()
{
SetEvent(_EventEnd);
}
inline DWORD Size()
{
return (DWORD)_lThreadNum;
}
inline DWORD GetRunningSize()
{
return (DWORD)_lRunningNum;
}
bool IsRunning()
{
return _lRunningNum > ;
}
protected:
//工作线程
static DWORD WINAPI DefaultJobProc(LPVOID lpParameter = NULL)
{
ThreadItem *pThread = static_cast<ThreadItem*>(lpParameter);
assert(pThread);
ThreadPool *pThreadPoolObj = pThread->_pThis;
assert(pThreadPoolObj);
InterlockedIncrement(&pThreadPoolObj->_lThreadNum);
HANDLE hWaitHandle[];
hWaitHandle[] = pThreadPoolObj->_SemaphoreCall;
hWaitHandle[] = pThreadPoolObj->_SemaphoreDel;
hWaitHandle[] = pThreadPoolObj->_EventEnd;
JobItem *pJob;
bool fHasJob;
for(;;)
{
DWORD wr = WaitForMultipleObjects(, hWaitHandle, false, INFINITE);
//响应删除线程信号
if(wr == WAIT_OBJECT_0 + )
break;
//从队列里取得用户作业
EnterCriticalSection(&pThreadPoolObj->_csWorkQueue);
if(fHasJob = !pThreadPoolObj->_JobQueue.empty())
{
pJob = pThreadPoolObj->_JobQueue.front();
pThreadPoolObj->_JobQueue.pop();
assert(pJob);
}
LeaveCriticalSection(&pThreadPoolObj->_csWorkQueue);
//受到结束线程信号 确定是否结束线程(结束线程信号 && 是否还有工作)
if(wr == WAIT_OBJECT_0 + && !fHasJob)
break;
if(fHasJob && pJob)
{
InterlockedIncrement(&pThreadPoolObj->_lRunningNum);
pThread->_dwLastBeginTime = GetTickCount();
pThread->_dwCount++;
pThread->_fIsRunning = true;
pJob->_pFunc(pJob->_pPara); //运行用户作业
delete pJob;
pThread->_fIsRunning = false;
InterlockedDecrement(&pThreadPoolObj->_lRunningNum);
}
}
//删除自身结构
EnterCriticalSection(&pThreadPoolObj->_csThreadVector);
pThreadPoolObj->_ThreadVector.erase(find(pThreadPoolObj->_ThreadVector.begin(), pThreadPoolObj->_ThreadVector.end(), pThread));
LeaveCriticalSection(&pThreadPoolObj->_csThreadVector);
delete pThread;
InterlockedDecrement(&pThreadPoolObj->_lThreadNum);
if(!pThreadPoolObj->_lThreadNum) //所有线程结束
SetEvent(pThreadPoolObj->_EventComplete);
return ;
}
//调用用户对象虚函数
static void CallProc(void *pPara)
{
CallProcPara *cp = static_cast<CallProcPara *>(pPara);
assert(cp);
if(cp)
{
cp->_pObj->DoJob(cp->_pPara);
delete cp;
}
}
//用户对象结构
struct CallProcPara
{
ThreadJob* _pObj;//用户对象
void *_pPara;//用户参数
CallProcPara(ThreadJob* p, void *pPara) : _pObj(p), _pPara(pPara) { };
};
//用户函数结构
struct JobItem
{
void (*_pFunc)(void *);//函数
void *_pPara; //参数
JobItem(void (*pFunc)(void *) = NULL, void *pPara = NULL) : _pFunc(pFunc), _pPara(pPara) { };
};
//线程池中的线程结构
struct ThreadItem
{
HANDLE _Handle; //线程句柄
ThreadPool *_pThis; //线程池的指针
DWORD _dwLastBeginTime; //最后一次运行开始时间
DWORD _dwCount; //运行次数
bool _fIsRunning;
ThreadItem(ThreadPool *pthis) : _pThis(pthis), _Handle(NULL), _dwLastBeginTime(), _dwCount(), _fIsRunning(false) { };
~ThreadItem()
{
if(_Handle)
{
CloseHandle(_Handle);
_Handle = NULL;
}
}
};
std::queue<JobItem *> _JobQueue; //工作队列
std::vector<ThreadItem *> _ThreadVector; //线程数据
CRITICAL_SECTION _csThreadVector, _csWorkQueue; //工作队列临界, 线程数据临界
HANDLE _EventEnd, _EventComplete, _SemaphoreCall, _SemaphoreDel;//结束通知, 完成事件, 工作信号, 删除线程信号
long _lThreadNum, _lRunningNum; //线程数, 运行的线程数
};
#endif //_ThreadPool_H_

转载自 http://blog.csdn.net/pjchen/archive/2004/11/06/170606.aspx

基本上是拿来就用了,对WIN32 API不熟,但对线程池的逻辑还是比较熟的,认为这个线程池写得很清晰,我拿来用在一个多线程下载的模块中。很实用的东东。
调用方法
void threadfunc(void *p)
{
     YourClass* yourObject = (YourClass*)    p;

//...
}
 ThreadPool tp;
 for(i=0; i<100; i++)
  tp.Call(threadfunc);

ThreadPool tp(20);//20为初始线程池规模

tp.Call(threadfunc, lpPara);

使用时注意几点:
1. ThreadJob  没什么用,直接写线程函数吧。 
2. 线程函数(threadfunc)的入口参数void* 可以转成自定义的类型对象,这个对象可以记录下线程运行中的数据,并设置线程当前状态,以此与线程进行交互。
3. 线程池有一个EndAndWait函数,用于让线程池中所有计算正常结束。有时线程池中的一个线程可能要运行很长时间,怎么办?可以通过线程函数threadfunc的入口参数对象来处理,比如:
class YourClass {
  int cmd; // cmd = 1是上线程停止计算,正常退出。
};
threadfunc(void* p) {
  YourClass* yourObject = (YourClass*)p;
  while (true) {
    // do some calculation
    if (yourClass->cmd == 1)
      break;
  }
}
在主线程中设置yourClass->cmd = 1,该线程就会自然结束。
很简洁通用的线程池实现。

【转】一个windows线程池实现的更多相关文章

  1. 第11章 Windows线程池(2)_Win2008及以上的新线程池

    11.2 Win2008以上的新线程池 (1)传统线程池的优缺点: ①传统Windows线程池调用简单,使用方便(有时只需调用一个API即可) ②这种简单也带来负面问题,如接口过于简单,无法更多去控制 ...

  2. 第11章 Windows线程池(1)_传统的Windows线程池

    第11章 Windows线程池 11.1 传统的Windows线程池及API (1)线程池中的几种底层线程 ①可变数量的长任务线程:WT_EXECUTELONGFUNCTION ②Timer线程:调用 ...

  3. windows线程池四种情形(win核心读书笔记)

    windows线程池四种情形(win核心读书笔记) Mircosoft从Windows2000引入线程池API,并在Vista后对线程池重新构架,引入新的线程池API.以下所有线程池函数均适用于Vis ...

  4. Windows核心编程:第11章 Windows线程池

    Github https://github.com/gongluck/Windows-Core-Program.git //第11章 Windows线程池.cpp: 定义应用程序的入口点. // #i ...

  5. 《Windows核心编程系列》十一谈谈Windows线程池

    Windows线程池 上一篇博文我们介绍了IO完成端口.得知IO完成端口可以非常智能的分派线程.但是IO完成端口仅对等待它的线程进行分派,创建和销毁线程的工作仍然需要我们自己来做. 我们自己也可以创建 ...

  6. 利用 Windows 线程池定制的 4 种方式完成任务(Windows 核心编程)

    Windows 线程池 说起底层的线程操作一般都不会陌生,Windows 提供了 CreateThread 函数来创建线程,为了同步线程的操作,Windows 提供了事件内核对象.互斥量内核对象.关键 ...

  7. 发一个可伸缩线程池大小的python线程池。已通过测试。

    发一个可伸缩线程池大小的线程池. 当任务不多时候,不开那么多线程,当任务多的时候开更多线程.当长时间没任务时候,将线程数量减小到一定数量. java的Threadpoolexcutor可以这样,py的 ...

  8. 第11章 Windows线程池(3)_私有的线程池

    11.3 私有的线程池 11.3.1 创建和销毁私有的线程池 (1)进程默认线程池 当调用CreateThreadpoolwork.CreateThreadpoolTimer.CreateThread ...

  9. 一个python线程池的源码解析

    python为了方便人们编程高度封装了很多东西,比如进程里的进程池,大大方便了人们编程的效率,但是默认却没有线程池,本人前段时间整理出一个线程池,并进行了简单的解析和注释,本人水平有限,如有错误希望高 ...

随机推荐

  1. POJ 2299 Ultra-QuickSort (排序+数据离散化+求顺序数)

    题意:给出一个序列,求至少需要用到多少次操作,才能将序列从小到大排序. 思路: 数据量很大,n<500000,所以用冒泡模拟是超时的. 接下来就想到了求顺序数,总共需要交换的次数为每个数后面有多 ...

  2. C# 在vs2010中打开vs2012的项目(转)

    在vs2010中打开vs2012的项目 今天在自己的电脑上装了vs2010然后要打开之前在vs2012上创建的sln文件 被提示-- 无法打开在新版本上创建的sln--解决方案--文件 其实vs201 ...

  3. POJ 2240 Arbitrage(floyd)

    http://poj.org/problem?id=2240 题意 : 好吧,又是一个换钱的题:套利是利用货币汇率的差异进行的货币转换,例如用1美元购买0.5英镑,1英镑可以购买10法郎,一法郎可以购 ...

  4. Android ListView点击失效

    item中存在 ImageButton 等可以点击的组件,这会抢先获得ListView的焦点. 从而导致item点击失效

  5. ssh 公钥

    以前做ssh key登录方式时都是用的root帐号,基本都是无往不利的,权限采用默认即可.今天实验中两台机器帐号都是nianzong,一个普通的帐号.按照如下步骤: A机器:ssh-keygen -t ...

  6. 深入理解JVM—Java 6 JVM参数配置说明

    原文地址:http://yhjhappy234.blog.163.com/blog/static/316328322011119111014657/ 使用说明< xmlnamespace pre ...

  7. 从SQL Server中导入/导出Excel的基本方法(转)

    从sql server中导入/导出 excel 的基本方法 /*=========== 导入/导出 excel 的基本方法 ===========*/ 从excel文档中,导入数据到sql数据库中,很 ...

  8. Apache 下SVN项目管理使用说明

    Apache 下SVN项目管理使用说明 (1)Apaceh和SVN先要装好. (2)在apache的目录下找到httpd.conf文件,在最后一行增加如下配置 Include conf/svn.pro ...

  9. Hibernate逍遥游记-第12章 映射值类型集合-003映射List(<list-index>)

    1. <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hi ...

  10. Android:储存方式之SharePreferences

    使用SharedPreferences保存数据,其实质是采用了xml文件存放数据, 存储位置:/data/data/<package name>/shared_prefs 写入: publ ...