線程池的使用

來源:互聯網
上載者:User
 

·                                 最近一位高手同事實現了一個線程池,代碼品質超一流的說。特把代碼發上來,還有相關的線程池的文檔。     在物件導向編程中,建立和銷毀對象是很費時間的,因為建立一個對象要擷取記憶體資源或者其它更多資源。在Java中更是如此,虛擬機器將試圖跟蹤每一個對象,以便能夠在對象銷毀後進行記憶體回收。所以提高服務程式效率的一個手段就是儘可能減少建立和銷毀對象的次數,特別是一些很耗資源的對象建立和銷毀。如何利用已有對象來服務就是一個需要解決的關鍵問題,其實這就是一些“池化資源”技術產生的原因。比如大家所熟悉的資料庫連接池正是遵循這一思想而產生的,本文將介紹的線程池技術同樣符合這一思想。    目前,一些著名的大公司都特別看好這項技術,並早已經在他們的產品中應用該技術。比如IBM的WebSphere,IONA的Orbix 2000在SUN的 Jini中,Microsoft的MTS(Microsoft Transaction Server 2.0),COM+等。    多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。但如果對多線程應用不當,會增加對單個任務的處理時間。可以舉一個簡單的例子:
假設在一台伺服器完成一項任務的時間為TT1 建立線程的時間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_#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;
 }
};struct IWorker// 工人
{
 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();protected:
 //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; HANDLE    m_hWorkerEvent;
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(); }
 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; //all the work threads
 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//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////CThreadPool::CThreadPool()
{
 m_nCurProcessingJobIndex = -1;
 m_bRemovingThread = FALSE;
 m_JobList.RemoveAll();
}CThreadPool::~CThreadPool()
{
 m_JobList.RemoveAll();
}void CThreadPool::Start(unsigned short nStatic, unsigned short 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 UINT 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);  TRACE1("generate a worker thread handle id is %d./n", threadId);
  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;
 //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; 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;
}unsigned int CThreadPool::ManagerProc(void* 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();
 } 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; DWORD threadId=::GetCurrentThreadId();
// 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);
  }
 } return 0;
}void CThreadPool::ChangeStatus(DWORD threadId, bool status)
{
 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); 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(); 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;  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) );
 }
}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;
 }
 
}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;
}文章引用自: http://blog.sina.com.cn/s/blog_4ab96a72010009sv.html

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.