线程池(译)

来源:互联网 发布:淘宝内裤 怎么卷的 编辑:程序博客网 时间:2024/05/17 06:57

这是我翻译的codeproject上面的一篇文章,题目是:线程池

一 简介

   我的应用中,需要将数据备份到不同的地方(CD,USB,网络共享)。如果我只用单线程来做这件事情,需要花2个小时以上。而如何改善性能对我来说是一个挑战,最终我用多线程来实现了这个问题,结果非常可观,只用了30分钟就完成了我的工作。

  其实在刚开始开发时,备份耗费了一整天,后来我被迫增加频率到1个小时。现在我发现了一个问题:实际中由于频率过低导致线程频繁的重复创建和销毁。怎么解决这个问题?为什么线程不能被重复利用呢?所以这就是线程池的由来。

  • 你是否需要线程池?
  • 你有多个请求需要被重复和并行处理吗?
  • 每个请求能独立工作吗?
  • 你需要等待IO/File操作吗?

如果你的回答是肯定的,那么线程池非常适合你。你的程序会因此具有低耦合性并且易于实现。

 

二 背景

  作为一名码农,你应该至少有过一次使用单线程的经历,我也无例外。现在我需要创建一个线程池并用C++实现,于是我Google并下载了很多例子,但是它们都不凑效,虽然例子很多,但是没有适合我需要的,所以我写下了这边文章。

  我为什么需要一个线程次?一般大多数的IO操作(比如文件,磁盘等)比较耗时,所以用单线程的话,很多系统资源(比如内存,处理器等)会处于等待状态,这显然是一种浪费。这时用多线程的话就能有效利用空闲时间,提高内存和处理器利用率。

  对于这些情况下的一些应用使用线程池会比较有效:

  • 它要求避免线程创建和销毁等操作带来的时间消耗
  • 它是并行的,而且会异步分发大量的小任务
  • 它会创建和销毁大量的线程(这些线程运行时间比较短)。用线程池的话会减少线程管理的复杂度,以及线程创建销毁负荷
  • 它会在后台并行处理一些独立的任务

  线程次的创建

    线程池会创建指定数量的线程并等待调用请求。一旦收到一个线程使用请求,它会激活一个线程并开始执行。等执行完成以后,这个线程会变成等待状态,然后等待下一次的请求。如果要求请求清除,所有的线程将会退出线程池。

关系图如下所示:

下面是其中的类的介绍:

  • ThreadPool

  这个类用于创建,管理和销毁线程池。在使用时,你可以创建一个ThreadPool的对象,并可以指定需要创建的线程数量。这里的线程池最大支持64个线程,它也可以减少至最小线程数以避免过度线程切换和系统资源消耗。

  • AbstractRequest

  这个类代表了对线程池的请求操作。客户端应用应该继承这个类,并重载其Execute()函数。并且你需要利用其提供的临界区对象来保证线程安全。取消操作可以通过IsAborted()函数来判断。把继承的抽象请求发送到线程池让其处理,也可以通过Abort()取消。

  • Logger

  线程池有错误信息和log记录功能。默认的log输出是在调试窗口。你也可以创建一个继承Logger的自定义的类并重载这个输出,并实现其中的LogError()和LogInfo()函数。然后将Logger类实例在线程池创建的时候传递给它就可以了。

下面这张图说明了如何在你的应用中使用线程池?

 

   应用程序中有一个ThreadPool的实例,当接收到创建请求时,这个类会创建指定数量的线程,每个线程都将等待被调用。一旦接收到请求,其中的一个线程将结束等待状态并开始处理请求。等处理完成以后,线程恢复到等待状态。用户在任何时候都能调用AbstractRequest的Abort()来中止请求过程。线程池在处理完请求后不会删除它。

 

三 示例

  • Create()
// Create thread pool with specified number of threads.bool Create( const unsigned short usThreadCount_i, Logger* pLogger_io = NULL );

这个函数将创建指定数量的线程并进入等待状态。如果指定了Logger,它将会被用来处理错误。这个函数失败时返回false,最大数量的线程数是64

  • Destroy()
// Destroy the existing thread pool.bool Destroy();

这个函数中止所有的请求并销毁线程池。失败时返回false。

  • PostRequest()
// Post request to thread pool for processing.bool PostRequest( AbstractRequest* pRequest_io );

这个函数发送指定的请求到线程池,失败时返回false

 

依赖关系

  ThreadPool.h 包含了windows.h, list.h (STL)string.h (STL)

 

如何在你的应用中使用线程池?

  1. 包含ThreadPool.hThreadPool.cpp
  2. 如果有需要,线程池可以打印错误信息到调试窗口,而且这个行为可以通过重载来实现。默认的行为可以从Logger来继承一个类,并重载LogError()和LogInfo()函数。
  3. 用Create()创建线程池,如果有需要的话可以提供Logger
  4. 创建一个继承自AbtractRequest的类,可以实现Execute()函数作为线程函数
  5. 创建继承自AbtractRequest的类实例,并传递给线程此用来处理PostRequest()函数。用户可以无限制的发送请求,但是被激活的请求数量等于线程数量
  6. 一旦处理完成以后,能调用Destroy()销毁线程池。

ThreadPoolDemo 是一个应用ThreadPool类的demo。这个线程池针对Windows操作系统,也可以移植到Linux和IOS平台。可以在本文最下面提供的下载链接获取。

这里是ThreadPool的代码:

  1 /**  2  * @author :    Suresh  3  */  4   5 #ifndef _THREAD_POOL_MGR_H_  6 #define _THREAD_POOL_MGR_H_  7   8 #include <windows.h>  9 #include <list> 10  11 namespace TP 12 { 13  14     /** 15      * Logger - This is base class for the error logger class and it is polymorphic. 16      *          The users of the ThreadPool create a class which derived from this  17      *          and override LogError() and LogInfo() for their own error logging mechanism. 18      *          The default error logging will be in output window. 19      */ 20     class Logger 21     { 22  23     public: 24  25         // Constructor 26         Logger(){}; 27         // Destructor 28         virtual ~Logger(){}; 29         // Log error description. 30         void LogError( const long lActiveReq_i, const std::wstring& wstrError_i ); 31         // Log information. 32         void LogInfo( const long lActiveReq_i, const std::wstring& wstrInfo_i ); 33         // Override this function to log errors. Default log will be in output window. 34         virtual void LogError( const std::wstring& wstrError_i ); 35         // Override this function to log informations. Default log will be in output window. 36         virtual void LogInfo( const std::wstring& wstrInfo_i ); 37  38     private: 39  40         // Log thread ID, Active thread count and last error. 41         void PrepareLog( const long lActiveReq_i, std::wstring& wstrLog_io ); 42     }; 43  44     /** 45      * SyncObject - The class is a wrapper of Critical section object to provide 46      *              synchronization for thread pool. 47      */ 48     class SyncObject 49     { 50  51     public: 52         // Constructor 53         SyncObject() 54         { 55             ::InitializeCriticalSection( &m_stCriticalSection ); 56         } 57  58         // Destructor 59         ~SyncObject() 60         { 61             ::DeleteCriticalSection( &m_stCriticalSection ); 62         } 63  64         // Lock critical section. 65         bool Lock() 66         { 67             ::EnterCriticalSection( &m_stCriticalSection ); 68             return true; 69         } 70  71         // Unlock critical section. 72         bool Unlock() 73         { 74             ::LeaveCriticalSection( &m_stCriticalSection ); 75             return true; 76         } 77  78     private: 79         SyncObject( const SyncObject& ); 80         SyncObject& operator = ( const SyncObject& ); 81  82     private: 83  84         // Critical section object. 85         CRITICAL_SECTION m_stCriticalSection; 86     }; 87  88     /** 89      * AutoLock - This class own synchronization object during construction and 90      *            release the ownership during the destruction. 91      */ 92     class AutoLock 93     { 94  95     public: 96  97         /**  98          * Parameterized constructor 99          * 100          * @param       LockObj_i - Synchronization object.101          * @return      Nil102          * @exception   Nil103          * @see         Nil104          * @since       1.0105          */106         AutoLock( SyncObject& LockObj_i ) : m_pSyncObject( &LockObj_i )107         {108             if( NULL != m_pSyncObject )109             {110                 m_pSyncObject->Lock();111             }112         }113 114         /** 115          * Destructor.116          * 117          * @param       Nil118          * @return      Nil119          * @exception   Nil120          * @see         Nil121          * @since       1.0122          */123         ~AutoLock()124         {125             if( NULL != m_pSyncObject )126             {127                 m_pSyncObject->Unlock();128                 m_pSyncObject = NULL;129             }130         }131 132     private:133         SyncObject* m_pSyncObject;134     };135 136 137     /**138      * AbstractRequest - This is abstract base class for the request to be processed in thread pool.139      *                   and it is polymorphic. The users of the ThreadPool must create a class 140      *                   which derived from this and override Execute() function.141      */142     class AbstractRequest143     {144 145     public:146         // Constructor147         AbstractRequest() : m_bAborted( false ), m_usRequestID( 0u ){}148         // Destructor149         virtual ~AbstractRequest(){}150         // Thread procedure to be override in derived class. This function should return if request aborted.151         // Abort request can check by calling IsAborted() function during time consuming operation.152         virtual long Execute() = 0;153         // Set request ID.154         void SetRequestID( unsigned short uRequestID_i )155         {156             AutoLock LockRequest( m_LockWorkerThread );157             m_usRequestID = uRequestID_i;158         }159         // Get request ID.160         unsigned short GetRequestID()161         {162             AutoLock LockRequest( m_LockWorkerThread );163             return m_usRequestID;164         }165         // Abort the processing of the request.166         void Abort()167         {168             AutoLock LockRequest( m_LockWorkerThread );169             m_bAborted = true;170         }171         // Clear abort flag for re-posting the same request.172         void ClearAbortFlag()173         {174             AutoLock LockRequest( m_LockWorkerThread );175             m_bAborted = false;176         }177 178     protected:179         // Check for the abort request180         bool IsAborted()181         {182             AutoLock LockRequest( m_LockWorkerThread );183             return m_bAborted;184         }185         // Prepare error or information log.186         void PrepareLog( std::wstring& wstrLog_io );187 188     protected:189         // Synchronization object for resource locking.190         SyncObject m_LockWorkerThread;191 192     private:193         // Abort flag.194         bool m_bAborted;195         // Request Identifier.196         unsigned short m_usRequestID;197 198     };199 200     /**201      * AutoCounter - Increment and decrement counter202      */203     class AutoCounter204     {205 206     public:207         // Constructor.208         AutoCounter( unsigned short& usCount_io,209                      SyncObject& Lock_io ) :210                      m_usCount( usCount_io ), m_LockThread( Lock_io )211         {212             AutoLock Lock( m_LockThread );213             m_usCount++;214         }215 216         // Destructor.217         ~AutoCounter()218         {219             AutoLock Lock( m_LockThread );220             m_usCount--;221         }222 223     private:224         // Counter variable.225         unsigned short& m_usCount;226         // Synchronization object for resource locking.227         SyncObject& m_LockThread;228     };229 230 231     typedef std::list<AbstractRequest*> REQUEST_QUEUE;232 233 234     /**235      * ThreadPool - This class create and destroy thread pool based on the request.236      *              The requested to be processed can be post to pool as derived object of 237      *              AbstractRequest. Also a class can be derive from Logger to error and238      *              information logging.239      */240     class ThreadPool241     {242 243     public:244         // Constructor.245         ThreadPool();246         // Destructor.247         ~ThreadPool();248 249         // Create thread pool with specified number of threads.250         bool Create( const unsigned short usThreadCount_i, Logger* pLogger_io = NULL );251         // Destroy the existing thread pool.252         bool Destroy();253         // Post request to thread pool for processing.254         bool PostRequest( AbstractRequest* pRequest_io );255 256     private:257         AbstractRequest* PopRequest( REQUEST_QUEUE& RequestQueue_io );258         bool AddThreads();259         bool NotifyThread();260         bool ProcessRequests();261         bool WaitForRequest();262         bool DestroyPool();263         bool IsDestroyed();264         void SetDestroyFlag( const bool bFlag_i );265         void CancelRequests();266         void LogError( const std::wstring& wstrError_i );267         void LogInfo( const std::wstring& wstrInfo_i );268         static UINT WINAPI ThreadProc( LPVOID pParam_i );269 270     private:271         ThreadPool( const ThreadPool& );272         ThreadPool& operator = ( const ThreadPool& );273 274     private:275         // Used for thread pool destruction.276         bool m_bDestroyed;277         // Hold thread count in the pool.278         unsigned short m_usThreadCount;279         // Released semaphore count.280         unsigned short m_usSemaphoreCount;281         // Active thread count.282         unsigned short m_lActiveThread;283         // Active thread count.284         unsigned short m_usPendingReqCount;285         // Manage active thread count in pool.286         HANDLE m_hSemaphore;287         // Hold thread handles.288         HANDLE* m_phThreadList;289         // Request queue.290         REQUEST_QUEUE m_RequestQueue;291         // Synchronization object for resource locking.292         SyncObject m_LockWorkerThread;293         // User defined error and information logger class.294         Logger* m_pLogger;295         // Default error and information logger.296         Logger m_Logger;297     };298 } // namespace TP299 300 #endif // #ifndef _THREAD_POOL_MGR_H_
ThreadPool.h
  1 /**  2  * @author :    Suresh  3  */  4   5 #include "ThreadPool.h"  6 #include <sstream>  7 #include <iomanip>  8   9 namespace TP 10 { 11  12     /**  13      * Log error description. 14      *  15      * @param       lActiveReq_i - Count of active requests. 16      * @param       wstrError_i  - Error message. 17      */ 18     void Logger::LogError( const long lActiveReq_i, const std::wstring& wstrError_i ) 19     { 20         std::wstring wstrLog( wstrError_i ); 21         PrepareLog( lActiveReq_i, wstrLog ); 22         LogError( wstrLog ); 23     } 24  25  26     /**  27      * Log information. 28      *  29      * @param       lActiveReq_i - Count of active requests. 30      * @param       wstrInfo_i   - Information message. 31      */ 32     void Logger::LogInfo( const long lActiveReq_i, const std::wstring& wstrInfo_i ) 33     { 34         std::wstring wstrLog( wstrInfo_i ); 35         PrepareLog( lActiveReq_i, wstrLog ); 36         LogInfo( wstrLog ); 37     } 38  39  40     /**  41      * Override this function to log errors. Default log will be in output window. 42      *  43      * @param       wstrError_i  - Error description 44      */ 45     void Logger::LogError( const std::wstring& wstrError_i ) 46     { 47         OutputDebugString( wstrError_i.c_str()); 48     } 49  50  51     /**  52      * Override this function to log informations. Default log will be in output window. 53      *  54      * @param       wstrInfo_i   - Information description. 55      */ 56     void Logger::LogInfo( const std::wstring& wstrInfo_i ) 57     { 58         OutputDebugString( wstrInfo_i.c_str()); 59     } 60  61  62     /**  63      * Log thread ID, Active thread count and last error. 64      *  65      * @param       lActiveReq_i - Active thread count. 66      * @param       wstrLog_io   - Error or information description 67      */ 68     void Logger::PrepareLog( const long lActiveReq_i, std::wstring& wstrLog_io ) 69     { 70         std::wstringstream wstrmLog; 71         wstrmLog << L"##TP## [TID=" << std::setfill( L'0' ) << std::setw(8) << ::GetCurrentThreadId() 72                  << L"] [ACTIVE REQUEST=" << std::setw(4) << lActiveReq_i 73                  << L"] [LAST ERROR=" << std::setw(4) << ::GetLastError() 74                  << L"] " << wstrLog_io.c_str() << + L"]"; 75         wstrLog_io = wstrmLog.str(); 76     } 77  78  79     /**  80      * Prepare error or information log. 81      *  82      * @param       wstrLog_io - Log information 83      */ 84     void AbstractRequest::PrepareLog( std::wstring& wstrLog_io ) 85     { 86         std::wstringstream wstrmLog; 87         wstrmLog << std::setfill( L'0' ); 88         wstrmLog << L"##RQ## [RID=" << std::setw(8) << GetRequestID() 89                  << L"] [Desc=" << wstrLog_io.c_str() << + L"]"; 90         wstrLog_io = wstrmLog.str(); 91     } 92  93  94     /**  95      * Constructor 96      */ 97     ThreadPool::ThreadPool() : m_bDestroyed( false ), 98                                m_usThreadCount( 0u ), 99                                m_usSemaphoreCount( 0u ),100                                m_lActiveThread( 0u ),101                                m_usPendingReqCount( 0u ),102                                m_hSemaphore( NULL ),103                                m_phThreadList( NULL ),104                                m_pLogger( &m_Logger )105     {106     }107 108 109     /** 110      * Destructor111      */112     ThreadPool::~ThreadPool()113     {114         if( NULL != m_phThreadList )115         {116             if( !Destroy())117             {118                 LogError( L"Destroy() failed" );119             }120         }121     }122 123 124     /** 125      * Create thread pool with specified number of threads.126      * 127      * @param       usThreadCount_i - Thread count.128      * @param       pLogger_i       - Logger instance to log errors and informations129      */130     bool ThreadPool::Create( const unsigned short usThreadCount_i, Logger* pLogger_i )131     {132         try133         {134             // Assign logger object. If user not provided then use existing and135             // error will be logged in output window.136             m_pLogger = ( NULL != pLogger_i ) ? pLogger_i : &m_Logger;137             // Check thread pool is initialized already.138             if( NULL != m_phThreadList )139             {140                 LogError( L"ThreadPool already created" );141                 return false;142             }143             // Validate thread count.144             if( 0 == usThreadCount_i )145             {146                 LogError( L"Minimum allowed thread count is one" );147                 return false;148             }149             if( usThreadCount_i > 64 )150             {151                 LogError( L"Maximum allowed thread count is 64" );152                 return false;153             }154             LogInfo( L"Thread pool creation requested" );155 156             // Initialize values.157             m_lActiveThread = 0u;158             m_usSemaphoreCount = 0u;159             m_usPendingReqCount = 0u;160             m_usThreadCount = usThreadCount_i;161             // Create semaphore for thread count management.162             m_hSemaphore = CreateSemaphore( NULL, 0, m_usThreadCount, NULL );163             if( NULL == m_hSemaphore )164             {165                 LogError( L"Semaphore creation failed" );166                 m_usThreadCount = 0u;167                 return false;168             }169             // Create worker threads and make pool active170             if( !AddThreads())171             {172                 LogError( L"Threads creation failed" );173                 Destroy();174                 return false;175             }176             SetDestroyFlag( false );177             LogInfo( L"Thread pool created successfully" );178             return true;179         }180         catch( ... )181         {182             LogError( L"Exception occurred in Create()" );183             return false;184         }185     }186 187 188     /** 189      * Destroy thread pool.190      */191     bool ThreadPool::Destroy()192     {193         try194         {195             // Check whether thread pool already destroyed.196             if( NULL == m_phThreadList )197             {198                 LogError( L"ThreadPool is already destroyed or not created yet" );199                 return false;200             }201             // Cancel all requests.202             CancelRequests();203             // Set destroyed flag to true for exiting threads.204             SetDestroyFlag( true );205             // Release remaining semaphores to exit thread.206             {207                 AutoLock LockThread( m_LockWorkerThread );208                 if( m_lActiveThread < m_usThreadCount )209                 {210                     if( NULL == ReleaseSemaphore( m_hSemaphore, m_usThreadCount - m_lActiveThread, NULL ))211                     {212                         LogError( L"Failed to release Semaphore" );213                         return false;214                     }215                 }216             }217             // Wait for destroy completion and clean the thread pool.218             if( !DestroyPool())219             {220                 LogError( L"Thread pool destruction failed" );221                 return false;222             }223             LogInfo( L"Thread Pool destroyed successfully" );224             return true;225         }226         catch( ... )227         {228             LogError( L"Exception occurred in Destroy()" );229             return false;230         }231     }232 233 234     /** 235      * Post request to thread pool for processing236      * 237      * @param       pRequest_io - Request to be processed.238      */239     bool ThreadPool::PostRequest( AbstractRequest* pRequest_io )240     {241         try242         {243             AutoLock LockThread( m_LockWorkerThread );244             if( NULL == m_phThreadList )245             {246                 LogError( L"ThreadPool is destroyed or not created yet" );247                 return false;248             }249             m_RequestQueue.push_back( pRequest_io );250             if( m_usSemaphoreCount < m_usThreadCount )251             {252                 // Thread available to process, so notify thread.253                 if( !NotifyThread())254                 {255                     LogError( L"NotifyThread failed" );256                     // Request notification failed. Try after some time.257                     m_usPendingReqCount++;258                     return false;259                 }260             }261             else262             {263                 // Thread not available to process.264                 m_usPendingReqCount++;265             }266             return true;267         }268         catch( ... )269         {270             LogError( L"Exception occurred in PostRequest()" );271             return false;272         }273     }274 275 276     /** 277      * Pop request from queue for processing.278      * 279      * @param       RequestQueue_io  - Request queue.280      * @return      AbstractRequest* - Request pointer.281      */282     AbstractRequest* ThreadPool::PopRequest( REQUEST_QUEUE& RequestQueue_io )283     {284         AutoLock LockThread( m_LockWorkerThread );285         if( !RequestQueue_io.empty())286         {287             AbstractRequest* pRequest = RequestQueue_io.front();288             RequestQueue_io.remove( pRequest );289             return pRequest;290         }291         return 0;292     }293 294 295     /** 296      * Create specified number of threads. Initial status of threads will be waiting.297      */298     bool ThreadPool::AddThreads()299     {300         try301         {302             // Allocate memory for all threads.303             m_phThreadList = new HANDLE[m_usThreadCount];304             if( NULL == m_phThreadList )305             {306                 LogError( L"Memory allocation for thread handle failed" );307                 return false;308             }309             // Create worker threads.310             DWORD dwThreadID = 0;311             for( unsigned short usIdx = 0u; usIdx < m_usThreadCount; usIdx++ )312             {313                 // Create worker thread314                 m_phThreadList[usIdx] = CreateThread( 0, 0,315                                                       reinterpret_cast<LPTHREAD_START_ROUTINE>( ThreadPool::ThreadProc ),316                                                       this, 0, &dwThreadID );317                 if( NULL == m_phThreadList[usIdx] )318                 {319                     LogError( L"CreateThread failed" );320                     return false;321                 }322             }323             return true;324         }325         catch( ... )326         {327             LogError( L"Exception occurred in AddThreads()" );328             return false;329         }330     }331 332 333     /** 334      * Add request to queue and release semaphore by one.335      */336     bool ThreadPool::NotifyThread()337     {338         try339         {340             AutoLock LockThread( m_LockWorkerThread );341             // Release semaphore by one to process this request.342             if( NULL == ReleaseSemaphore( m_hSemaphore, 1, NULL ))343             {344                 LogError( L"ReleaseSemaphore failed" );345                 return false;346             }347             m_usSemaphoreCount++;348             return true;349         }350         catch( ... )351         {352             LogError( L"Exception occurred in NotifyThread()" );353             m_RequestQueue.pop_back();354             return false;355         }356     }357 358 359     /** 360      * Process request in queue.361      */362     bool ThreadPool::ProcessRequests()363     {364         bool bContinue( true );365         do366         {367             try368             {369                 LogInfo( L"Thread WAITING" );370                 // Wait for request.371                 if( !WaitForRequest())372                 {373                     LogError( L"WaitForRequest() failed" );374                     continue;375                 }376                 // Thread counter.377                 AutoCounter Counter( m_lActiveThread, m_LockWorkerThread );378                 LogInfo( L"Thread ACTIVE" );379                 // Check thread pool destroy request.380                 if( IsDestroyed())381                 {382                     LogInfo( L"Thread EXITING" );383                     break;384                 }385                 // Get request from request queue.386                 AbstractRequest* pRequest = PopRequest( m_RequestQueue );387                 if( NULL == pRequest )388                 {389                     LogError( L"PopRequest failed" );390                     continue;391                 }392                 // Execute the request.393                 long lReturn = pRequest->Execute();394                 if( NULL != lReturn )395                 {396                     LogError( L"Request execution failed" );397                     continue;398                 }399                 // Check thread pool destroy request.400                 if( IsDestroyed())401                 {402                     LogInfo( L"Thread EXITING" );403                     break;404                 }405                 AutoLock LockThread( m_LockWorkerThread );406                 // Inform thread if any pending request.407                 if( m_usPendingReqCount > 0 )408                 {409                     if( m_usSemaphoreCount < m_usThreadCount )410                     {411                         // Thread available to process, so notify thread.412                         if( !NotifyThread())413                         {414                             LogError( L"NotifyThread failed" );415                             continue;416                         }417                         m_usPendingReqCount--;418                     }419                 }420             }421             catch( ... )422             {423                 LogError( L"Exception occurred in ProcessRequests()" );424                 continue;425             }426         }427         while( bContinue );428         return true;429     }430 431 432     /** 433      * Wait for request queuing to thread pool.434      */435     bool ThreadPool::WaitForRequest()436     {437         try438         {439             // Wait released when requested queued.440             DWORD dwReturn = WaitForSingleObject( m_hSemaphore, INFINITE );441             if( WAIT_OBJECT_0 != dwReturn )442             {443                 LogError( L"WaitForSingleObject failed" );444                 return false;445             }446             AutoLock LockThread( m_LockWorkerThread );447             m_usSemaphoreCount--;448             // Clear previous error.449             ::SetLastError( 0 );450             return true;451         }452         catch( ... )453         {454             LogError( L"Exception occurred in WaitForRequest()" );455             return false;456         }457     }458 459 460     /** 461      * Destroy and clean up thread pool.462      */463     bool ThreadPool::DestroyPool()464     {465         try466         {467             // Wait for the exist of threads.468             DWORD dwReturn = WaitForMultipleObjects( m_usThreadCount, m_phThreadList, TRUE, INFINITE );469             if( WAIT_OBJECT_0 != dwReturn )470             {471                 LogError( L"WaitForMultipleObjects failed" );472                 return false;473             }474             // Close all threads.475             for( USHORT uIdx = 0u; uIdx < m_usThreadCount; uIdx++ )476             {477                 if( TRUE != CloseHandle( m_phThreadList[uIdx] ))478                 {479                     LogError( L"CloseHandle failed for threads" );480                     return false;481                 }482             }483             // Clear memory allocated for threads.484             delete[] m_phThreadList;485             m_phThreadList = 0;486             // Close the semaphore487             if( TRUE != CloseHandle( m_hSemaphore ))488             {489                 LogError( L"CloseHandle failed for semaphore" );490                 return false;491             }492             // Clear request queue.493             m_RequestQueue.clear();494             return true;495         }496         catch( ... )497         {498             LogError( L"Exception occurred in DestroyPool()" );499             return false;500         }501     }502 503 504     /** 505      * Check for destroy request.506      */507     inline bool ThreadPool::IsDestroyed()508     {509         // Avoid synchronization issues if destroy requested after validation.510         AutoLock LockThread( m_LockWorkerThread );511         // During thread pool destruction all semaphores are released512         // to exit all threads.513         return m_bDestroyed;514     }515 516 517     /** 518      * Set destroy flag519      */520     inline void ThreadPool::SetDestroyFlag( const bool bFlag_i )521     {522         AutoLock LockThread( m_LockWorkerThread );523         m_bDestroyed = bFlag_i;524     }525 526 527     /** 528      * Cancel all processing request in pool.529      */530     void ThreadPool::CancelRequests()531     {532         try533         {534             // Avoid synchronization issues if destroy requested after validation.535             AutoLock LockThread( m_LockWorkerThread );536             LogInfo( L"Thread pool destroy requested" );537             // Clear main queue.538             m_RequestQueue.clear();539         }540         catch( ... )541         {542             LogError( L"Exception occurred in CancelRequests()" );543         }544     }545 546 547     /** 548      * Log error in thread pool.549      * 550      * @param       wstrError_i - Error description.551      */552     void ThreadPool::LogError( const std::wstring& wstrError_i )553     {554         if( NULL != m_pLogger )555         {556             m_pLogger->LogError( m_lActiveThread, wstrError_i );557         }558     }559 560 561     /** 562      * Log information in thread pool.563      * 564      * @param       wstrInfo_i - Information description.565      */566     void ThreadPool::LogInfo( const std::wstring& wstrInfo_i )567     {568         if( NULL != m_pLogger )569         {570             m_pLogger->LogInfo( m_lActiveThread, wstrInfo_i );571         }572     }573 574 575     /** 576      * worker thread procedure.577      * 578      * @param       pParam_i - ThreadPool instance.579      * @return      UINT      - Return 0 on success.580      */581     UINT ThreadPool::ThreadProc( LPVOID pParam_i )582     {583         ThreadPool* pThreadPool = NULL;584         try585         {586             ThreadPool* pThreadPool = reinterpret_cast<ThreadPool*>( pParam_i );587             if( NULL == pThreadPool )588             {589                 return 1;590             }591             if( !pThreadPool->ProcessRequests())592             {593                 pThreadPool->LogError( L"ProcessRequests() failed" );594                 return 1;595             }596             return 0;597         }598         catch( ... )599         {600             if( NULL !=  pThreadPool )601             {602                 pThreadPool->LogError( L"Exception occurred in ThreadProc()" );603             }604             return 1;605         }606     }607 } // namespace TP
ThreadPool.cpp

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

 *****************************************************************************************************************************************************

英文原文:http://www.codeproject.com/Articles/637708/Thread-Pool

源代码   :http://files.cnblogs.com/wb-DarkHorse/ThreadPool.zip
 
另外一篇讲线程池的文章:http://www.codeproject.com/Tips/579294/A-Perfect-ThreadPool-in-Windows-Cplusplus
 
0 0
原创粉丝点击