线程池浅析及C++代码实现

来源:互联网 发布:淘宝苹果授权书 编辑:程序博客网 时间:2024/06/05 15:54

线程池浅析及C++代码实现

(1)什么是线程池

线程池是一种多线程处理技术。线程池先创建好若干线程,并管理这些线程。当有新的任务到来时,将任务添加到一个已创建的空闲线程中执行。线程池所创建的线程优先级都是一样的,所以需要使用特定线程优先级的任务不宜使用线程池。

(2)线程池的优点和应用

线程池统一管理线程的方式减少了频繁创建和销毁线程的系统调度开销,很大程度上提高了服务器处理并发任务的性能。

线程池适用于频繁的任务调度,如处理HTTP请求,任务多,并且任务周期小

(3)C++代码实现

#include "stdafx.h"

 

#include "stdafx.h"  

#include <assert.h>  

#include <windows.h>

#include <map>

#include <iostream>

 

using namespace std;

 

class ITask

{

public:

     virtual void ProcessTask(void* pUser)=0;

};

//線程池

class CThreadPool  

{

public:

     class ThreadInfo

     {

     public:      

         ThreadInfo() { m_hThread=0;m_bBusyWorking=false;}

         ThreadInfo(HANDLEhandle, boolbBusy) { m_hThread=handle; m_bBusyWorking=bBusy; }

         ThreadInfo(const ThreadInfo& info){ m_hThread=info.m_hThread; m_bBusyWorking=info.m_bBusyWorking;}

        

         HANDLE m_hThread;

         bool m_bBusyWorking;

     };

 

     typedef map<DWORD,ThreadInfo>ThreadInfoMap;

     typedef ThreadInfoMap::iterator  Iterator_ThreadInfoMap;

 

     enum ThreadPoolStatus{ STATUS_BUSY, STATUS_IDLE,STATUS_NORMAL };

public:

     CThreadPool()

     {

         InitializeCriticalSection(&m_CS);

     }

     virtual ~CThreadPool()

     {

         DeleteCriticalSection(&m_CS);

     }

 

     bool Start(unsigned short nStatic, unsigned short nMax)  

     {  

         if(nMax<nStatic)

         {

              assert(0);

              return false;

         }

         HANDLE  hThread;  

         DWORD   nThreadId;  

         m_nNumberOfStaticThreads=nStatic;  

         m_nNumberOfTotalThreads=nMax;  

 

         //lock the resource  

         EnterCriticalSection(&m_CS);

 

         //create an IO port  

         m_hMgrIoPort = CreateIoCompletionPort((HANDLE)INVALID_HANDLE_VALUE,NULL, 0, 0);  

         hThread = CreateThread(  

              NULL,                                          // SD  

              0,                                             // initial stack size  

              (LPTHREAD_START_ROUTINE)ManagerProc,    // threadfunction  

              (LPVOID)this,                             // thread argument  

              0,                                            // creationoption  

              &nThreadId );                             // thread identifier  

         m_hMgrThread = hThread;  

 

         //now we start these worker threads  

         m_hWorkerIoPort = CreateIoCompletionPort((HANDLE)INVALID_HANDLE_VALUE,NULL, 0, 0);  

         for(long n = 0; n < nStatic; n++)

         {  

              hThread = CreateThread(  

                   NULL, // SD  

                   0,                        // initial stack size  

                   (LPTHREAD_START_ROUTINE)WorkerProc,    // threadfunction  

                   (LPVOID)this,                       //thread argument  

                   0,                    //creation option  

                   &nThreadId );      

              m_threadMap.insert(m_threadMap.end(),ThreadInfoMap::value_type(nThreadId,ThreadInfo(hThread, false)));  

         }  

 

         LeaveCriticalSection(&m_CS);

         return true;

     }  

 

     void Stop(bool bHash = false)  

     {  

         EnterCriticalSection(&m_CS);  

 

         ::PostQueuedCompletionStatus(m_hMgrIoPort, 0, 0, (OVERLAPPED*)0xFFFFFFFF);  

         WaitForSingleObject(m_hMgrThread,INFINITE);  

         CloseHandle(m_hMgrThread);  

         CloseHandle(m_hMgrIoPort);  

 

         //shut down all the worker threads  

         UINT nCount=m_threadMap.size();  

         HANDLE* pThread= new HANDLE[nCount];  

         long n=0;  

         ThreadInfo info;  

         Iterator_ThreadInfoMap i=m_threadMap.begin();  

         while(i!=m_threadMap.end())  

         {  

              ::PostQueuedCompletionStatus(m_hWorkerIoPort, 0, 0, (OVERLAPPED*)0xFFFFFFFF);  

              info=i->second;  

              pThread[n++]=info.m_hThread;  

              i++;  

         }  

 

         DWORD rc=WaitForMultipleObjects(nCount,pThread, TRUE,30000);//wait for 0.5 minutes, then start to killthreads  

         CloseHandle(m_hWorkerIoPort);  

         if(rc>=WAIT_OBJECT_0 && rc<WAIT_OBJECT_0+nCount)  

         {  

              for(unsigned int n=0;n<nCount;n++)  

              {  

                   CloseHandle(pThread[n]);  

              }  

         }  

         else if(rc==WAIT_TIMEOUT&&bHash)  

         {  

              //some threadsnot terminated, we have to stop them.  

              DWORD exitCode;  

              for(unsigned int i=0; i<nCount; i++)  

              {  

                   if (::GetExitCodeThread(pThread[i],&exitCode)==STILL_ACTIVE)  

                   {  

                       TerminateThread(pThread[i], 99);  

                   }  

                   CloseHandle(pThread[i]);  

              }  

         }  

         delete[] pThread;  

 

         LeaveCriticalSection(&m_CS);

     }  

 

     void AddTask(void* pUser, ITask* pWorker)const  

     {  

         ::PostQueuedCompletionStatus(m_hWorkerIoPort, \

              reinterpret_cast<DWORD>(pWorker), \

              reinterpret_cast<DWORD>(pUser),\

              NULL);  

     }  

 

protected:

     HANDLE GetMgrIoPort()const { return m_hMgrIoPort; }

     UINT GetMgrWaitTime()const { return1000; }

     HANDLE GetWorkerIoPort()const { return m_hWorkerIoPort; }

 

private:

     static DWORD WINAPI WorkerProc(void* p)  

     {  

         //convert the parameter to the server pointer.  

         CThreadPool* pServer=(CThreadPool*)p;  

         HANDLE                              IoPort  = pServer->GetWorkerIoPort();  

         unsigned long                       pN1,pN2;   

         OVERLAPPED*                         pOverLapped;  

 

         DWORD threadId=::GetCurrentThreadId();  

 

         while(::GetQueuedCompletionStatus(IoPort, &pN1,&pN2,   

              &pOverLapped, INFINITE))  

         {  

              if(pOverLapped ==(OVERLAPPED*)0xFFFFFFFE)  

              {  

                   pServer->RemoveThread(threadId);  

                   break;  

              }  

              else if(pOverLapped == (OVERLAPPED*)0xFFFFFFFF)  

              {  

                   break;  

              }  

              else  

              {  

                   pServer->SetStatus(threadId, true);  

                   //retrieve the job description and agent pointer  

                   ITask* pTask = reinterpret_cast<ITask*>(pN1);  

                   void* pUser= reinterpret_cast<void*>(pN2);  

                   pTask->ProcessTask(pUser);  

                   pServer->SetStatus(threadId, false);  

              }  

         }  

         return 0;  

     }  

 

 

     static DWORD WINAPI ManagerProc(void* p)  

     {  

         //convert the parameter to the server pointer.  

         CThreadPool* pServer=(CThreadPool*)p;  

         HANDLE                              IoPort  = pServer->GetMgrIoPort();  

         unsigned long                       pN1,pN2;   

         OVERLAPPED*                         pOverLapped;  

 

     LABEL_MANAGER_PROCESSING:  

         while(::GetQueuedCompletionStatus(IoPort, &pN1,&pN2,   

              &pOverLapped, pServer->GetMgrWaitTime() ))  

         {  

              if(pOverLapped ==(OVERLAPPED*)0xFFFFFFFF)  

              {  

                   return 0;  

              }  

         }  

 

         //time out processing  

         if (::GetLastError()==WAIT_TIMEOUT)  

         {  

              //the manager will take a look at all the worker's status.The  

              if (pServer->GetStatus()==STATUS_BUSY)  

                   pServer->AddThreads();  

              if (pServer->GetStatus()==STATUS_IDLE)  

                   pServer->RemoveThreads();  

 

              goto LABEL_MANAGER_PROCESSING;  

         }  

         return 0;  

     }  

 

protected:

     //manager thread

     HANDLE m_hMgrThread;

     HANDLE m_hMgrIoPort;

     protected:

     //configuration parameters

     mutable unsigned short m_nNumberOfStaticThreads;

     mutable unsigned short m_nNumberOfTotalThreads;

 

protected:

     //helper functions

     void CThreadPool::AddThreads()  

     {  

         HANDLE  hThread;  

         DWORD   nThreadId;  

         unsigned int nCount=m_threadMap.size();  

         unsigned int nTotal=min(nCount+2, m_nNumberOfTotalThreads);  

         for(unsigned int i=0; i<nTotal-nCount; i++)  

         {  

              hThread = CreateThread(  

                   NULL, // SD  

                   0,                        // initial stack size  

                   (LPTHREAD_START_ROUTINE)WorkerProc,    // threadfunction  

                   (LPVOID)this,                       //thread argument  

                   0,                    //creation option  

                   &nThreadId );      

 

              m_threadMap.insert(m_threadMap.end(),ThreadInfoMap::value_type(nThreadId,ThreadInfo(hThread, false)));  

         }  

     }  

 

     void RemoveThreads()  

     {  

         unsigned int nCount=m_threadMap.size();  

         unsigned int nTotal=max(nCount-2, m_nNumberOfStaticThreads);  

         for(unsigned int i=0; i<nCount-nTotal; i++)  

         {  

              ::PostQueuedCompletionStatus(m_hWorkerIoPort, 0, 0, (OVERLAPPED*)0xFFFFFFFE);  

         }  

     }  

 

     ThreadPoolStatus GetStatus()  

     {  

         int nTotal = m_threadMap.size();  

         ThreadInfo info;  

         int nCount=0;  

         Iterator_ThreadInfoMap i=m_threadMap.begin();   

         while(i!=m_threadMap.end())  

         {  

              info=i->second;  

              if (info.m_bBusyWorking==true)nCount++;  

              i++;  

         }  

         if ( nCount/(1.0*nTotal) > 0.8 )  

              return STATUS_BUSY;  

         if ( nCount/ (1.0*nTotal) < 0.2 )  

              return STATUS_IDLE;  

         return STATUS_NORMAL;

     }  

 

     void SetStatus(DWORD threadId,bool status)  

     {  

         EnterCriticalSection(&m_CS);  

 

         Iterator_ThreadInfoMap i;  

         ThreadInfo info;  

         i=m_threadMap.find(threadId);  

         info=i->second;  

        

         info.m_bBusyWorking=status;  

         m_threadMap.insert(m_threadMap.end(),ThreadInfoMap::value_type(threadId, info));  

 

         LeaveCriticalSection(&m_CS);

     }  

 

     void CThreadPool::RemoveThread(DWORDthreadId)  

     {  

         EnterCriticalSection(&m_CS);

         m_threadMap.erase(threadId);  

         LeaveCriticalSection(&m_CS);

     }  

 

protected:

     //all the work threads

     ThreadInfoMap m_threadMap;

     CRITICAL_SECTION m_CS;

     HANDLE m_hWorkerIoPort;

};

 

////////////////////測試代碼////////////////////////////////////

class CTest:public ITask

{

public:

     CTest()

     {

         static int ii = 0;

         m_ii = ii ++;

     }

 

     void ProcessTask(void* pUser)

     {

         for(int i = 0; i <3; i ++)

         {

              cout<<"TaskID: "<<((CTest*)pUser)->m_ii<<endl;

              Sleep(100);

         }

 

     }

 

     ~CTest()

     {

 

     }

private:

     int m_ii;

};

 

int _tmain(int argc, _TCHAR* argv[])

{

     CThreadPool *pPool= new CThreadPool();

     const int TEST_COUNT = 8;

     CTest test[TEST_COUNT];

    

     //啟動線程池,5個處理線程,最多接受10個任務

     pPool->Start(5,10);

 

   //添加任務到線程池中

     for(int i = 0; i < TEST_COUNT; i++)

         pPool->AddTask(&test[i], &test[i]);

        

     cin.get();

    //停止線程池

     pPool->Stop();

 

     return 0;

}