00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifndef PTLIB_THREADPOOL_H
00036 #define PTLIB_THREADPOOL_H
00037
00038 #ifdef P_USE_PRAGMA
00039 #pragma interface
00040 #endif
00041
00042 #include <map>
00043
00044
00129 class PThreadPoolBase : public PObject
00130 {
00131 public:
00132 class WorkerThreadBase : public PThread
00133 {
00134 public:
00135 WorkerThreadBase()
00136 : PThread(100, NoAutoDeleteThread, NormalPriority, "Pool")
00137 , m_shutdown(false)
00138 { }
00139
00140 virtual void Shutdown() = 0;
00141 virtual unsigned GetWorkSize() const = 0;
00142
00143 bool m_shutdown;
00144 PMutex m_workerMutex;
00145 };
00146
00147 class InternalWorkBase
00148 {
00149 public:
00150 InternalWorkBase(const char * group)
00151 {
00152 if (group != NULL)
00153 m_group = group;
00154 }
00155 std::string m_group;
00156 };
00157
00158 PThreadPoolBase(unsigned maxWorkerCount = 10, unsigned maxWorkUnitCount = 0);
00159 ~PThreadPoolBase();
00160
00161 virtual WorkerThreadBase * CreateWorkerThread() = 0;
00162 virtual WorkerThreadBase * AllocateWorker();
00163
00164 protected:
00165 virtual bool CheckWorker(WorkerThreadBase * worker);
00166 void StopWorker(WorkerThreadBase * worker);
00167 PMutex m_listMutex;
00168
00169 typedef std::vector<WorkerThreadBase *> WorkerList_t;
00170 WorkerList_t m_workers;
00171
00172 unsigned m_maxWorkerCount;
00173 unsigned m_maxWorkUnitCount;
00174 };
00175
00176
00177 template <class Work_T>
00178 class PThreadPool : public PThreadPoolBase
00179 {
00180 PCLASSINFO(PThreadPool, PThreadPoolBase);
00181 public:
00182
00183
00184
00185 class WorkerThread : public WorkerThreadBase
00186 {
00187 public:
00188 WorkerThread(PThreadPool & pool_)
00189 : m_pool(pool_)
00190 {
00191 }
00192
00193 virtual void AddWork(Work_T * work) = 0;
00194 virtual void RemoveWork(Work_T * work) = 0;
00195 virtual void Main() = 0;
00196
00197 protected:
00198 PThreadPool & m_pool;
00199 };
00200
00201
00202
00203
00204 class InternalWork : public InternalWorkBase
00205 {
00206 public:
00207 InternalWork(WorkerThread * worker, Work_T * work, const char * group)
00208 : InternalWorkBase(group)
00209 , m_worker(worker)
00210 , m_work(work)
00211 {
00212 }
00213
00214 WorkerThread * m_worker;
00215 Work_T * m_work;
00216 };
00217
00218
00219
00220
00221 typedef std::map<Work_T *, InternalWork> ExternalToInternalWorkMap_T;
00222 ExternalToInternalWorkMap_T m_externalToInternalWorkMap;
00223
00224
00225
00226
00227
00228 struct GroupInfo {
00229 unsigned m_count;
00230 WorkerThread * m_worker;
00231 };
00232
00233
00234
00235
00236
00237 typedef std::map<std::string, GroupInfo> GroupInfoMap_t;
00238 GroupInfoMap_t m_groupInfoMap;
00239
00240
00241
00242
00243
00244 PThreadPool(unsigned maxWorkers = 10, unsigned maxWorkUnits = 0)
00245 : PThreadPoolBase(maxWorkers, maxWorkUnits)
00246 { }
00247
00248
00249
00250
00251
00252 bool AddWork(Work_T * work, const char * group = NULL)
00253 {
00254 PWaitAndSignal m(m_listMutex);
00255
00256
00257
00258 WorkerThread * worker;
00259 if ((group == NULL) || (strlen(group) == 0)) {
00260 worker = (WorkerThread *)AllocateWorker();
00261 }
00262 else {
00263
00264
00265 typename GroupInfoMap_t::iterator g = m_groupInfoMap.find(group);
00266 if (g == m_groupInfoMap.end())
00267 worker = (WorkerThread *)AllocateWorker();
00268 else {
00269 worker = g->second.m_worker;
00270 PTRACE(4, "ThreadPool\tAllocated worker thread by group Id " << group);
00271 }
00272 }
00273
00274
00275 if (worker == NULL)
00276 return false;
00277
00278
00279 InternalWork internalWork(worker, work, group);
00280
00281
00282 m_externalToInternalWorkMap.insert(typename ExternalToInternalWorkMap_T::value_type(work, internalWork));
00283
00284
00285 if (!internalWork.m_group.empty()) {
00286 typename GroupInfoMap_t::iterator r = m_groupInfoMap.find(internalWork.m_group);
00287 if (r != m_groupInfoMap.end())
00288 ++r->second.m_count;
00289 else {
00290 GroupInfo info;
00291 info.m_count = 1;
00292 info.m_worker = worker;
00293 m_groupInfoMap.insert(typename GroupInfoMap_t::value_type(internalWork.m_group, info));
00294 }
00295 }
00296
00297
00298 worker->AddWork(work);
00299
00300 return true;
00301 }
00302
00303
00304
00305
00306 bool RemoveWork(Work_T * work, bool removeFromWorker = true)
00307 {
00308 PWaitAndSignal m(m_listMutex);
00309
00310
00311 typename ExternalToInternalWorkMap_T::iterator r = m_externalToInternalWorkMap.find(work);
00312 if (r == m_externalToInternalWorkMap.end())
00313 return false;
00314
00315 InternalWork & internalWork = r->second;
00316
00317
00318 if (removeFromWorker)
00319 internalWork.m_worker->RemoveWork(work);
00320
00321
00322 if (!internalWork.m_group.empty()) {
00323 typename GroupInfoMap_t::iterator r = m_groupInfoMap.find(internalWork.m_group);
00324 PAssert(r != m_groupInfoMap.end(), "Attempt to find thread from unknown work group");
00325 if (r != m_groupInfoMap.end()) {
00326 if (--r->second.m_count == 0)
00327 m_groupInfoMap.erase(r);
00328 }
00329 }
00330
00331
00332 CheckWorker(internalWork.m_worker);
00333
00334
00335 m_externalToInternalWorkMap.erase(r);
00336
00337 return true;
00338 }
00339 };
00340
00341
00342 #endif // PTLIB_THREADPOOL_H
00343
00344
00345