线程池的使用(转载)
来源:互联网 发布:Javascript算法 编辑:程序博客网 时间:2024/04/30 14:17
· 最近一位高手同事实现了一个线程池,代码质量超一流的说。特把代码发上来,还有相关的线程池的文档。
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些“池化资源”技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想。
目前,一些著名的大公司都特别看好这项技术,并早已经在他们的产品中应用该技术。比如IBM的WebSphere,IONA的Orbix 2000在SUN的 Jini中,Microsoft的MTS(Microsoft Transaction Server 2.0),COM+等。
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:
假设在一台服务器完成一项任务的时间为T
假设在一台服务器完成一项任务的时间为T
T1 创建线程的时间
T2 在线程中执行任务的时间,包括线程间同步所需时间
T3 线程销毁的时间
显然T = T1+T2+T3。注意这是一个极度简化的假设。
可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
下面是线程池的实现代码:
ThreadPool.h
// ThreadPool.h: interface for the CThreadPool class.
//
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_THREADPOOL_H__E60DFA90_8F3E_11D4_8AF0_0000C03A07C8__INCLUDED_)
#define AFX_THREADPOOL_H__E60DFA90_8F3E_11D4_8AF0_0000C03A07C8__INCLUDED_
#define AFX_THREADPOOL_H__E60DFA90_8F3E_11D4_8AF0_0000C03A07C8__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <afxmt.h>
#include <afxtempl.h>
struct IJobDesc// 工作
{
public:
BOOL m_bProcessing;//工作正在处理中
IJobDesc()
{
m_bProcessing = FALSE;
}
};
#pragma once
#endif // _MSC_VER > 1000
#include <afxmt.h>
#include <afxtempl.h>
struct IJobDesc// 工作
{
public:
BOOL m_bProcessing;//工作正在处理中
IJobDesc()
{
m_bProcessing = FALSE;
}
};
struct IWorker// 工人
{
virtual void ProcessJob(IJobDesc* pJob)=0;
};
{
virtual void ProcessJob(IJobDesc* pJob)=0;
};
class CThreadPool
{
friend static unsigned int __stdcall CThreadPool::ManagerProc(void* p);
friend static unsigned int __stdcall CThreadPool::WorkerProc(void* p);
protected:
enum ThreadPoolStatus { BUSY, IDLE, NORMAL };
public:
//interface to the outside
void Start(unsigned short nStatic, unsigned short nmax);
void Stop(bool bHash=false);
void AddJob(IJobDesc* pJob, IWorker* pWorker);
void RemoveJob(IJobDesc* pJob);
//constructor and destructor
CThreadPool();
virtual ~CThreadPool();
CThreadPool();
virtual ~CThreadPool();
protected:
//interfaces public:
//interfaces public:
UINT GetMgrWaitTime() const { return 1000*6; }
private:
static unsigned int __stdcall ManagerProc(void* p);
static unsigned int __stdcall WorkerProc(void* p);
protected:
//manager thread
HANDLE m_hMgrThread;
HANDLE m_hMhtEvent;
static unsigned int __stdcall ManagerProc(void* p);
static unsigned int __stdcall WorkerProc(void* p);
protected:
//manager thread
HANDLE m_hMgrThread;
HANDLE m_hMhtEvent;
HANDLE m_hWorkerEvent;
protected:
//configuration parameters
mutable UINT m_nNumberOfStaticThreads;
mutable UINT m_nNumberOfTotalThreads;
protected:
//configuration parameters
mutable UINT m_nNumberOfStaticThreads;
mutable UINT m_nNumberOfTotalThreads;
protected:
//helper functions
void AddThreads();
void RemoveThreads();
ThreadPoolStatus GetThreadPoolStatus();
void ChangeStatus(DWORD threadId, bool status);
void RemoveThread(DWORD threadId)
{
CSingleLock lock(&m_arrayCs);
lock.Lock();
m_threadMap.RemoveKey(threadId);
m_bRemovingThread = FALSE;
lock.Unlock();
//helper functions
void AddThreads();
void RemoveThreads();
ThreadPoolStatus GetThreadPoolStatus();
void ChangeStatus(DWORD threadId, bool status);
void RemoveThread(DWORD threadId)
{
CSingleLock lock(&m_arrayCs);
lock.Lock();
m_threadMap.RemoveKey(threadId);
m_bRemovingThread = FALSE;
lock.Unlock();
}
BOOL GetNextProcessJob(IJobDesc ** pJob, IWorker** pWorker);
BOOL GetNextProcessJob(IJobDesc ** pJob, IWorker** pWorker);
protected:
struct ThreadInfo
{
HANDLE m_hThread;
bool m_bBusyWorking;
ThreadInfo() { m_hThread=0; m_bBusyWorking=false; }
ThreadInfo(HANDLE handle, bool bBusy) { m_hThread=handle; m_bBusyWorking=bBusy; }
ThreadInfo(const ThreadInfo& info) { m_hThread=info.m_hThread; m_bBusyWorking=info.m_bBusyWorking; }
};
typedef struct JobInfo
{
IJobDesc * pJob;
IWorker * pWorker;
}JOBINFO;
CArray<JobInfo,JobInfo&>m_JobList;
CCriticalSection m_sJoblistSection;
int m_nCurProcessingJobIndex;
CCriticalSection m_IndexSection;
struct ThreadInfo
{
HANDLE m_hThread;
bool m_bBusyWorking;
ThreadInfo() { m_hThread=0; m_bBusyWorking=false; }
ThreadInfo(HANDLE handle, bool bBusy) { m_hThread=handle; m_bBusyWorking=bBusy; }
ThreadInfo(const ThreadInfo& info) { m_hThread=info.m_hThread; m_bBusyWorking=info.m_bBusyWorking; }
};
typedef struct JobInfo
{
IJobDesc * pJob;
IWorker * pWorker;
}JOBINFO;
CArray<JobInfo,JobInfo&>m_JobList;
CCriticalSection m_sJoblistSection;
int m_nCurProcessingJobIndex;
CCriticalSection m_IndexSection;
//all the work threads
CMap<DWORD, DWORD&, ThreadInfo, ThreadInfo&> m_threadMap;
CCriticalSection m_arrayCs;
CMap<DWORD, DWORD&, ThreadInfo, ThreadInfo&> m_threadMap;
CCriticalSection m_arrayCs;
BOOL m_bRemovingThread;
};
};
#endif // !defined(AFX_THREADPOOL_H__E60DFA90_8F3E_11D4_8AF0_0000C03A07C8__INCLUDED_)
文章引用自:
· ThreadPool.cpp
// ThreadPool.cpp: implementation of the CThreadPool class.
//
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ThreadPool.h"
#include "process.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#include "ThreadPool.h"
#include "process.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CThreadPool::CThreadPool()
{
m_nCurProcessingJobIndex = -1;
m_bRemovingThread = FALSE;
m_JobList.RemoveAll();
}
{
m_nCurProcessingJobIndex = -1;
m_bRemovingThread = FALSE;
m_JobList.RemoveAll();
}
CThreadPool::~CThreadPool()
{
m_JobList.RemoveAll();
}
{
m_JobList.RemoveAll();
}
void CThreadPool::Start(unsigned short nStatic, unsigned short nMax)
{
ASSERT(nMax>=nStatic);
m_nNumberOfStaticThreads=nStatic;
m_nNumberOfTotalThreads=nMax;
{
ASSERT(nMax>=nStatic);
m_nNumberOfStaticThreads=nStatic;
m_nNumberOfTotalThreads=nMax;
m_hMhtEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hWorkerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//lock the resource
CSingleLock singleLock(&m_arrayCs);
singleLock.Lock(); // Attempt to lock the shared resource
m_hWorkerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//lock the resource
CSingleLock singleLock(&m_arrayCs);
singleLock.Lock(); // Attempt to lock the shared resource
UINT dwThreadId;
m_hMgrThread = (HANDLE)_beginthreadex(NULL, 0, &ManagerProc, this, 0, (unsigned*)&dwThreadId);
m_hMgrThread = (HANDLE)_beginthreadex(NULL, 0, &ManagerProc, this, 0, (unsigned*)&dwThreadId);
for(long n = 0; n < nStatic; n++)
{
DWORD threadId;
HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, &WorkerProc, this, 0, (unsigned*)&threadId);
{
DWORD threadId;
HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, &WorkerProc, this, 0, (unsigned*)&threadId);
TRACE1("generate a worker thread handle id is %d./n", threadId);
m_threadMap.SetAt(threadId, ThreadInfo(handle, false) );
}
singleLock.Unlock();
}
m_threadMap.SetAt(threadId, ThreadInfo(handle, false) );
}
singleLock.Unlock();
}
void CThreadPool::Stop(bool bHash)
{
CSingleLock singleLock(&m_arrayCs);
singleLock.Lock(); // Attempt to lock the shared resource
SetEvent(m_hMhtEvent);
WaitForSingleObject(m_hMgrThread, INFINITE);
CloseHandle(m_hMhtEvent);
m_hMhtEvent = NULL;
{
CSingleLock singleLock(&m_arrayCs);
singleLock.Lock(); // Attempt to lock the shared resource
SetEvent(m_hMhtEvent);
WaitForSingleObject(m_hMgrThread, INFINITE);
CloseHandle(m_hMhtEvent);
m_hMhtEvent = NULL;
//shut down all the worker threads
UINT nCount=m_threadMap.GetCount();
HANDLE* pThread = new HANDLE[nCount];
long n=0;
POSITION pos=m_threadMap.GetStartPosition();
DWORD threadId; ThreadInfo info;
while(pos!=NULL)
{
m_threadMap.GetNextAssoc(pos, threadId, info);
pThread[n++]=info.m_hThread;
}
singleLock.Unlock();
SetEvent(m_hWorkerEvent);
DWORD rc=WaitForMultipleObjects(nCount, pThread, TRUE, 120000);//wait for 2 minutes, then start to kill threads
CloseHandle(m_hWorkerEvent);
m_hWorkerEvent = NULL;
SetEvent(m_hWorkerEvent);
DWORD rc=WaitForMultipleObjects(nCount, pThread, TRUE, 120000);//wait for 2 minutes, then start to kill threads
CloseHandle(m_hWorkerEvent);
m_hWorkerEvent = NULL;
if(rc==WAIT_TIMEOUT&&bHash)
{
//some threads not terminated, we have to stop them.
DWORD exitCode;
for(int i=0; i<nCount; i++)
if (::GetExitCodeThread(pThread[i], &exitCode)==STILL_ACTIVE)
TerminateThread(pThread[i], 99);
}
delete[] pThread;
}
{
//some threads not terminated, we have to stop them.
DWORD exitCode;
for(int i=0; i<nCount; i++)
if (::GetExitCodeThread(pThread[i], &exitCode)==STILL_ACTIVE)
TerminateThread(pThread[i], 99);
}
delete[] pThread;
}
unsigned int CThreadPool::ManagerProc(void* p)
{
//convert the parameter to the server pointer.
CThreadPool* pServer=(CThreadPool*)p;
{
//convert the parameter to the server pointer.
CThreadPool* pServer=(CThreadPool*)p;
while(WAIT_OBJECT_0 != WaitForSingleObject(pServer->m_hMhtEvent, 6000))
{
//time out processing
TRACE0("Time out processing!/n");
//the manager will take a look at all the worker's status. The
if (pServer->GetThreadPoolStatus()==CThreadPool::BUSY)
pServer->AddThreads();
if (pServer->GetThreadPoolStatus()==CThreadPool::IDLE)
pServer->RemoveThreads();
}
{
//time out processing
TRACE0("Time out processing!/n");
//the manager will take a look at all the worker's status. The
if (pServer->GetThreadPoolStatus()==CThreadPool::BUSY)
pServer->AddThreads();
if (pServer->GetThreadPoolStatus()==CThreadPool::IDLE)
pServer->RemoveThreads();
}
return 0;
}
}
unsigned int CThreadPool::WorkerProc(void* p)
{
//convert the parameter to the server pointer.
CThreadPool* pServer=(CThreadPool*)p;
IWorker* pIWorker = NULL;
IJobDesc* pIJob= NULL;
{
//convert the parameter to the server pointer.
CThreadPool* pServer=(CThreadPool*)p;
IWorker* pIWorker = NULL;
IJobDesc* pIJob= NULL;
DWORD threadId=::GetCurrentThreadId();
// TRACE1("worker thread id is %d./n", threadId);
// TRACE1("worker thread id is %d./n", threadId);
while(true)
{
if(pServer->m_bRemovingThread)
{
pServer->RemoveThread(threadId);
break;
}
// TRACE(L"threadId %d:: begin GetTickCount %d /n",threadId,GetTickCount());
if (WAIT_OBJECT_0 == WaitForSingleObject(pServer->m_hWorkerEvent, 1))
{
break;
}
// TRACE(L"threadId %d:: end GetTickCount %d /n",threadId,GetTickCount());
if (pServer->GetNextProcessJob(&pIJob,&pIWorker))
{
// TRACE0("worker events comes in!/n");
//before processing, we need to change the status to busy.
pServer->ChangeStatus(threadId, true);
//retrieve the job description and agent pointer
if (pIJob && pIWorker)
{
pIJob->m_bProcessing = TRUE;
pIWorker->ProcessJob(pIJob);
pIJob->m_bProcessing = FALSE;
}
pServer->ChangeStatus(threadId, false);
}
}
{
if(pServer->m_bRemovingThread)
{
pServer->RemoveThread(threadId);
break;
}
// TRACE(L"threadId %d:: begin GetTickCount %d /n",threadId,GetTickCount());
if (WAIT_OBJECT_0 == WaitForSingleObject(pServer->m_hWorkerEvent, 1))
{
break;
}
// TRACE(L"threadId %d:: end GetTickCount %d /n",threadId,GetTickCount());
if (pServer->GetNextProcessJob(&pIJob,&pIWorker))
{
// TRACE0("worker events comes in!/n");
//before processing, we need to change the status to busy.
pServer->ChangeStatus(threadId, true);
//retrieve the job description and agent pointer
if (pIJob && pIWorker)
{
pIJob->m_bProcessing = TRUE;
pIWorker->ProcessJob(pIJob);
pIJob->m_bProcessing = FALSE;
}
pServer->ChangeStatus(threadId, false);
}
}
return 0;
}
}
void CThreadPool::ChangeStatus(DWORD threadId, bool status)
{
CSingleLock singleLock(&m_arrayCs);
singleLock.Lock(); // Attempt to lock the shared resource
{
CSingleLock singleLock(&m_arrayCs);
singleLock.Lock(); // Attempt to lock the shared resource
//retrieve the current thread handle
ThreadInfo info;
m_threadMap.Lookup(threadId, info);
info.m_bBusyWorking=status;
m_threadMap.SetAt(threadId, info);
ThreadInfo info;
m_threadMap.Lookup(threadId, info);
info.m_bBusyWorking=status;
m_threadMap.SetAt(threadId, info);
singleLock.Unlock();
}
}
void CThreadPool::AddJob(IJobDesc* pJob, IWorker* pWorker)
{
CThreadPool::JobInfo jobinfo;
jobinfo.pJob = pJob;
jobinfo.pWorker = pWorker;
CSingleLock lock(&m_sJoblistSection,TRUE);
m_JobList.Add(jobinfo);
}
void CThreadPool::RemoveJob(IJobDesc* pJob)
{
int size = m_JobList.GetSize();
JOBINFO jobinfo;
for (int i = 0; i < size ; i ++)
{
jobinfo = m_JobList.GetAt(i);
if (jobinfo.pJob == pJob)
{
CSingleLock lock(&m_sJoblistSection,TRUE);
m_JobList.RemoveAt(i);
return ;
}
}
}
BOOL CThreadPool::GetNextProcessJob(IJobDesc** pJob, IWorker** pWorker)
{
int size = m_JobList.GetSize();
if (size <= 0) return FALSE;
JOBINFO jobinfo;
//lock the resource
CSingleLock singleLock(&m_IndexSection);
singleLock.Lock(); //
m_nCurProcessingJobIndex ++;
if (m_nCurProcessingJobIndex >= size)
m_nCurProcessingJobIndex = 0;
jobinfo = m_JobList.GetAt(m_nCurProcessingJobIndex);
while (jobinfo.pJob && jobinfo.pJob->m_bProcessing && m_nCurProcessingJobIndex < size) {
m_nCurProcessingJobIndex ++;
if (m_nCurProcessingJobIndex < size)
jobinfo = m_JobList.GetAt(m_nCurProcessingJobIndex);
}
singleLock.Unlock();
{
CThreadPool::JobInfo jobinfo;
jobinfo.pJob = pJob;
jobinfo.pWorker = pWorker;
CSingleLock lock(&m_sJoblistSection,TRUE);
m_JobList.Add(jobinfo);
}
void CThreadPool::RemoveJob(IJobDesc* pJob)
{
int size = m_JobList.GetSize();
JOBINFO jobinfo;
for (int i = 0; i < size ; i ++)
{
jobinfo = m_JobList.GetAt(i);
if (jobinfo.pJob == pJob)
{
CSingleLock lock(&m_sJoblistSection,TRUE);
m_JobList.RemoveAt(i);
return ;
}
}
}
BOOL CThreadPool::GetNextProcessJob(IJobDesc** pJob, IWorker** pWorker)
{
int size = m_JobList.GetSize();
if (size <= 0) return FALSE;
JOBINFO jobinfo;
//lock the resource
CSingleLock singleLock(&m_IndexSection);
singleLock.Lock(); //
m_nCurProcessingJobIndex ++;
if (m_nCurProcessingJobIndex >= size)
m_nCurProcessingJobIndex = 0;
jobinfo = m_JobList.GetAt(m_nCurProcessingJobIndex);
while (jobinfo.pJob && jobinfo.pJob->m_bProcessing && m_nCurProcessingJobIndex < size) {
m_nCurProcessingJobIndex ++;
if (m_nCurProcessingJobIndex < size)
jobinfo = m_JobList.GetAt(m_nCurProcessingJobIndex);
}
singleLock.Unlock();
if (m_nCurProcessingJobIndex >= size) return FALSE;
*pJob = jobinfo.pJob;
*pWorker = jobinfo.pWorker;
return TRUE;
}
void CThreadPool::AddThreads()
{
int nCount=m_threadMap.GetCount();
int nTotal=min(nCount+2, m_nNumberOfTotalThreads);
for(int i=0; i<nTotal-nCount; i++)
{
if (i > 1) break;
*pWorker = jobinfo.pWorker;
return TRUE;
}
void CThreadPool::AddThreads()
{
int nCount=m_threadMap.GetCount();
int nTotal=min(nCount+2, m_nNumberOfTotalThreads);
for(int i=0; i<nTotal-nCount; i++)
{
if (i > 1) break;
DWORD threadId;
HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, &WorkerProc, this, 0, (unsigned*)&threadId);
TRACE1("generate a worker thread handle id is %d./n", threadId);
m_threadMap.SetAt(threadId, ThreadInfo(handle, false) );
}
}
HANDLE handle = (HANDLE)_beginthreadex(NULL, 0, &WorkerProc, this, 0, (unsigned*)&threadId);
TRACE1("generate a worker thread handle id is %d./n", threadId);
m_threadMap.SetAt(threadId, ThreadInfo(handle, false) );
}
}
void CThreadPool::RemoveThreads()
{
if (m_bRemovingThread) return;
int nCount=m_threadMap.GetCount();
int nTotal=max(nCount-2, m_nNumberOfStaticThreads);
if (nCount > nTotal)
{
CSingleLock lock(&m_arrayCs,TRUE);
m_bRemovingThread = TRUE;
}
}
{
if (m_bRemovingThread) return;
int nCount=m_threadMap.GetCount();
int nTotal=max(nCount-2, m_nNumberOfStaticThreads);
if (nCount > nTotal)
{
CSingleLock lock(&m_arrayCs,TRUE);
m_bRemovingThread = TRUE;
}
}
CThreadPool::ThreadPoolStatus CThreadPool::GetThreadPoolStatus()
{
int nTotal = m_threadMap.GetCount();
POSITION pos=m_threadMap.GetStartPosition();
DWORD threadId; ThreadInfo info;
int nCount=0;
while(pos!=NULL)
{
m_threadMap.GetNextAssoc(pos, threadId, info);
if (info.m_bBusyWorking==true) nCount++;
}
if ( nCount/(1.0*nTotal) > 0.8 )
return BUSY;
if ( nCount/ (1.0*nTotal) < 0.2 )
return IDLE;
return NORMAL;
}
{
int nTotal = m_threadMap.GetCount();
POSITION pos=m_threadMap.GetStartPosition();
DWORD threadId; ThreadInfo info;
int nCount=0;
while(pos!=NULL)
{
m_threadMap.GetNextAssoc(pos, threadId, info);
if (info.m_bBusyWorking==true) nCount++;
}
if ( nCount/(1.0*nTotal) > 0.8 )
return BUSY;
if ( nCount/ (1.0*nTotal) < 0.2 )
return IDLE;
return NORMAL;
}
文章引用自:
http://blog.sina.com.cn/s/blog_4ab96a72010009sv.html
- 线程池的使用(转载)
- 线程池的原理及使用(转载)
- 线程池(转载)
- 【转载】Linux下通用线程池的创建与使用
- 【转载】Java线程池的分析和使用
- 使用c++11写个最简跨平台线程池(转载)
- android的线程(转载)
- 【转载】线程池ThreadPoolExecutor使用简介
- 转载 一个C#线程池的例子
- Vector 是线程安全的?(转载)
- 进程和线程的区别(转载)
- 使用线程更新UI(转载)
- 【转载】互斥锁pthread_mutex_t的使用(转载)
- .NET 线程池编程技术(转载)
- java四种线程池(转载)
- 转载一篇线程池
- 从使用到原理学习Java线程池 (转载)
- 线程池的使用
- Pointers On C_读书笔记(一)
- JSF使用注意点
- setAttribute
- 筛选王 for Economist.com
- .NET Framework 3.5 中的功能简介(1)
- 线程池的使用(转载)
- DES算法代码
- crtexe.c作用
- 何时使用泛型集合
- 读<<Windows核心编程>>之进程准备篇 读书笔记
- 道冲,而用之有弗盈也。
- js树形菜单(梯形,没有+号)-主要是通过 display 控制
- 在VFP中分离中英字符串
- GIS 兵临战国,江山舍我其谁--开篇