线程池(译)
来源:互联网 发布:淘宝内裤 怎么卷的 编辑:程序博客网 时间: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)
如何在你的应用中使用线程池?
- 包含ThreadPool.h和ThreadPool.cpp
- 如果有需要,线程池可以打印错误信息到调试窗口,而且这个行为可以通过重载来实现。默认的行为可以从Logger来继承一个类,并重载LogError()和LogInfo()函数。
- 用Create()创建线程池,如果有需要的话可以提供Logger
- 创建一个继承自AbtractRequest的类,可以实现Execute()函数作为线程函数
- 创建继承自AbtractRequest的类实例,并传递给线程此用来处理PostRequest()函数。用户可以无限制的发送请求,但是被激活的请求数量等于线程数量
- 一旦处理完成以后,能调用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_
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
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- 线程池(译)
- 线程与线程池
- 线程池 线程优先级
- Executor线程,线程池
- 线程、多线程、线程池
- IOS-线程、线程池
- Java线程:线程池
- 线程和线程池
- 线程、多线程、线程池
- 线程、多线程、线程池
- 线程(六)线程池
- ExecutorService(线程池)+线程
- 线程和线程池
- 线程&线程池 简略
- 线程和线程池
- 线程池 线程锁
- 线程、线程池总结
- 线程与线程池
- c++模板函数实例化的偏序机制
- 插入排序与快速排序
- java File类中的mkdir()和mkdirs()的区别
- 如何利用循环代替递归以防止栈溢出(译)
- 大一时的BB
- 线程池(译)
- creep
- Binary Tree Postorder Traversal
- javascript中数组的定义及使用
- 如何创建一个简单的C++同步锁框架(译)
- 高考后的BB
- 关于宏##的使用注意一点
- 等别人一起去包夜时的BB
- 汉诺塔游戏