blob: a5b8f05b465ca729ad4fd64a5094d2333623d6a9 [file] [log] [blame]
Marc Slemko66949872006-07-15 01:52:39 +00001#include "ThreadManager.h"
Marc Slemkod466b212006-07-20 00:04:18 +00002#include "Exception.h"
Marc Slemko0e53ccd2006-07-17 23:51:05 +00003#include "Monitor.h"
Marc Slemko66949872006-07-15 01:52:39 +00004
Marc Slemko6f038a72006-08-03 18:58:09 +00005#include <boost/shared_ptr.hpp>
6
Marc Slemko66949872006-07-15 01:52:39 +00007#include <assert.h>
Marc Slemko0e53ccd2006-07-17 23:51:05 +00008#include <queue>
9#include <set>
Marc Slemko66949872006-07-15 01:52:39 +000010
Marc Slemko6f038a72006-08-03 18:58:09 +000011#if defined(DEBUG)
12#include <iostream>
13#endif //defined(DEBUG)
14
Marc Slemko66949872006-07-15 01:52:39 +000015namespace facebook { namespace thrift { namespace concurrency {
16
Marc Slemko6f038a72006-08-03 18:58:09 +000017using namespace boost;
18
Marc Slemkofe5ba12e2006-07-20 21:16:27 +000019
Marc Slemko66949872006-07-15 01:52:39 +000020/** ThreadManager class
21
22 This class manages a pool of threads. It uses a ThreadFactory to create threads. It never actually creates or destroys worker threads, rather
Marc Slemkod466b212006-07-20 00:04:18 +000023 it maintains statistics on number of idle threads, number of active threads, task backlog, and average wait and service times.
Marc Slemko66949872006-07-15 01:52:39 +000024
25 @author marc
Marc Slemko0e53ccd2006-07-17 23:51:05 +000026 @version $Id:$ */
27
28class ThreadManager::Impl : public ThreadManager {
29
30 public:
31
Marc Slemko6f038a72006-08-03 18:58:09 +000032 Impl() :
33 _workerCount(0),
34 _workerMaxCount(0),
35 _idleCount(0),
36 _state(ThreadManager::UNINITIALIZED)
37 {}
Marc Slemkod466b212006-07-20 00:04:18 +000038
Marc Slemko6f038a72006-08-03 18:58:09 +000039 ~Impl() {
40 stop();
41 }
Marc Slemkod466b212006-07-20 00:04:18 +000042
Marc Slemkofe5ba12e2006-07-20 21:16:27 +000043 void start();
Marc Slemko0e53ccd2006-07-17 23:51:05 +000044
Marc Slemkod466b212006-07-20 00:04:18 +000045 void stop();
Marc Slemko0e53ccd2006-07-17 23:51:05 +000046
Marc Slemkofe5ba12e2006-07-20 21:16:27 +000047 const ThreadManager::STATE state() const {
48 return _state;
49 };
50
Marc Slemko6f038a72006-08-03 18:58:09 +000051 shared_ptr<ThreadFactory> threadFactory() const {
Marc Slemko0e53ccd2006-07-17 23:51:05 +000052
53 Synchronized s(_monitor);
54
55 return _threadFactory;
56 }
57
Marc Slemko6f038a72006-08-03 18:58:09 +000058 void threadFactory(shared_ptr<ThreadFactory> value) {
Marc Slemko0e53ccd2006-07-17 23:51:05 +000059
60 Synchronized s(_monitor);
61
62 _threadFactory = value;
63 }
64
Marc Slemkod466b212006-07-20 00:04:18 +000065 void addWorker(size_t value);
Marc Slemko0e53ccd2006-07-17 23:51:05 +000066
Marc Slemkod466b212006-07-20 00:04:18 +000067 void removeWorker(size_t value);
Marc Slemko0e53ccd2006-07-17 23:51:05 +000068
69 size_t idleWorkerCount() const {return _idleCount;}
70
71 size_t workerCount() const {
72
73 Synchronized s(_monitor);
74
Marc Slemkod466b212006-07-20 00:04:18 +000075 return _workerCount;
Marc Slemko0e53ccd2006-07-17 23:51:05 +000076 }
77
78 size_t pendingTaskCount() const {
79
80 Synchronized s(_monitor);
81
82 return _tasks.size();
83 }
84
85 size_t totalTaskCount() const {
86
87 Synchronized s(_monitor);
88
Marc Slemkod466b212006-07-20 00:04:18 +000089 return _tasks.size() + _workerCount - _idleCount;
Marc Slemko0e53ccd2006-07-17 23:51:05 +000090 }
91
Marc Slemko6f038a72006-08-03 18:58:09 +000092 void add(shared_ptr<Runnable> value);
Marc Slemko0e53ccd2006-07-17 23:51:05 +000093
Marc Slemko6f038a72006-08-03 18:58:09 +000094 void remove(shared_ptr<Runnable> task);
Marc Slemko0e53ccd2006-07-17 23:51:05 +000095
96private:
97
Marc Slemkod466b212006-07-20 00:04:18 +000098 size_t _workerCount;
Marc Slemko0e53ccd2006-07-17 23:51:05 +000099
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000100 size_t _workerMaxCount;
101
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000102 size_t _idleCount;
103
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000104 ThreadManager::STATE _state;
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000105
Marc Slemko6f038a72006-08-03 18:58:09 +0000106 shared_ptr<ThreadFactory> _threadFactory;
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000107
108 friend class ThreadManager::Task;
109
Marc Slemko6f038a72006-08-03 18:58:09 +0000110 std::queue<shared_ptr<Task> > _tasks;
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000111
112 Monitor _monitor;
113
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000114 Monitor _workerMonitor;
115
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000116 friend class ThreadManager::Worker;
117
Marc Slemko6f038a72006-08-03 18:58:09 +0000118 std::set<shared_ptr<Thread> > _workers;
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000119
Marc Slemko6f038a72006-08-03 18:58:09 +0000120 std::set<shared_ptr<Thread> > _deadWorkers;
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000121};
Marc Slemko66949872006-07-15 01:52:39 +0000122
123class ThreadManager::Task : public Runnable {
124
125public:
126 enum STATE {
127 WAITING,
128 EXECUTING,
129 CANCELLED,
130 COMPLETE
131 };
132
Marc Slemko6f038a72006-08-03 18:58:09 +0000133 Task(shared_ptr<Runnable> runnable) :
Marc Slemko66949872006-07-15 01:52:39 +0000134 _runnable(runnable),
135 _state(WAITING)
136 {}
137
138 ~Task() {};
139
140 void run() {
141 if(_state == EXECUTING) {
142 _runnable->run();
143 _state = COMPLETE;
144 }
145 }
146
147 private:
148
Marc Slemko6f038a72006-08-03 18:58:09 +0000149 shared_ptr<Runnable> _runnable;
Marc Slemkod466b212006-07-20 00:04:18 +0000150
151 friend class ThreadManager::Worker;
Marc Slemko66949872006-07-15 01:52:39 +0000152
153 STATE _state;
154};
155
156class ThreadManager::Worker: public Runnable {
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000157
Marc Slemko66949872006-07-15 01:52:39 +0000158 enum STATE {
159 UNINITIALIZED,
160 STARTING,
161 STARTED,
162 STOPPING,
163 STOPPED
164 };
165
166 public:
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000167
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000168 Worker(ThreadManager::Impl* manager) :
Marc Slemko66949872006-07-15 01:52:39 +0000169 _manager(manager),
170 _state(UNINITIALIZED),
171 _idle(false)
172 {}
173
174 ~Worker() {}
175
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000176 bool isActive() const { return _manager->_workerCount <= _manager->_workerMaxCount;}
177
Marc Slemko66949872006-07-15 01:52:39 +0000178 /** Worker entry point
179
180 As long as worker thread is running, pull tasks off the task queue and execute. */
181
182 void run() {
183
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000184 bool active = false;
185
186 bool notifyManager = false;
187
188 /** Increment worker semaphore and notify manager if worker count reached desired max
189
190 Note
191 We have to release the monitor and acquire the workerMonitor since that is what the manager
192 blocks on for worker add/remove */
193
Marc Slemko8a40a762006-07-19 17:46:50 +0000194 {Synchronized s(_manager->_monitor);
Marc Slemko66949872006-07-15 01:52:39 +0000195
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000196 active = _manager->_workerCount < _manager->_workerMaxCount;
197
198 if(active) {
199
200 _manager->_workerCount++;
201
202 notifyManager = _manager->_workerCount == _manager->_workerMaxCount;
Marc Slemko66949872006-07-15 01:52:39 +0000203 }
204 }
205
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000206 if(notifyManager) {
207
208 Synchronized s(_manager->_workerMonitor);
209
210 _manager->_workerMonitor.notify();
211
212 notifyManager = false;
213 }
214
215 while(active) {
Marc Slemko66949872006-07-15 01:52:39 +0000216
Marc Slemko6f038a72006-08-03 18:58:09 +0000217 shared_ptr<ThreadManager::Task> task;
Marc Slemko66949872006-07-15 01:52:39 +0000218
219 /* While holding manager monitor block for non-empty task queue (Also check that the thread hasn't been requested to stop).
220
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000221 Once the queue is non-empty, dequeue a task, release monitor, and execute. If the worker max count has been decremented
222 such that we exceed it, mark ourself inactive, decrement the worker count and notify the manager (technically we're notifying
223 the next blocked thread but eventually the manager will see it. */
Marc Slemko66949872006-07-15 01:52:39 +0000224
Marc Slemko8a40a762006-07-19 17:46:50 +0000225 {Synchronized s(_manager->_monitor);
Marc Slemko66949872006-07-15 01:52:39 +0000226
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000227 active = isActive();
228
229 while(active && _manager->_tasks.empty()) {
Marc Slemko66949872006-07-15 01:52:39 +0000230
231 _manager->_idleCount++;
232
233 _idle = true;
234
235 _manager->_monitor.wait();
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000236
237 active = isActive();
Marc Slemko66949872006-07-15 01:52:39 +0000238
239 _idle = false;
240
241 _manager->_idleCount--;
242 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000243
244 if(active) {
Marc Slemkod466b212006-07-20 00:04:18 +0000245
246 if(!_manager->_tasks.empty()) {
Marc Slemko66949872006-07-15 01:52:39 +0000247
Marc Slemkod466b212006-07-20 00:04:18 +0000248 task = _manager->_tasks.front();
249
250 _manager->_tasks.pop();
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000251
Marc Slemkod466b212006-07-20 00:04:18 +0000252 if(task->_state == ThreadManager::Task::WAITING) {
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000253
Marc Slemkod466b212006-07-20 00:04:18 +0000254 task->_state = ThreadManager::Task::EXECUTING;
255 }
256 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000257 } else {
258
259 _idle = true;
260
261 _manager->_workerCount--;
262
263 notifyManager = _manager->_workerCount == _manager->_workerMaxCount;
Marc Slemko66949872006-07-15 01:52:39 +0000264 }
265 }
266
267 if(task != NULL) {
268
Marc Slemkod466b212006-07-20 00:04:18 +0000269 if(task->_state == ThreadManager::Task::EXECUTING) {
270 try {
271
272 task->run();
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000273
Marc Slemkod466b212006-07-20 00:04:18 +0000274 } catch(...) {
275
276 // XXX need to log this
277 }
Marc Slemkod466b212006-07-20 00:04:18 +0000278 }
Marc Slemko66949872006-07-15 01:52:39 +0000279 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000280 }
281
282 {Synchronized s(_manager->_workerMonitor);
283
284 _manager->_deadWorkers.insert(this->thread());
Marc Slemkod466b212006-07-20 00:04:18 +0000285
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000286 if(notifyManager) {
Marc Slemko66949872006-07-15 01:52:39 +0000287
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000288 _manager->_workerMonitor.notify();
Marc Slemko66949872006-07-15 01:52:39 +0000289 }
290 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000291
Marc Slemko66949872006-07-15 01:52:39 +0000292 return;
293 }
294
295 private:
296
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000297 ThreadManager::Impl* _manager;
Marc Slemko66949872006-07-15 01:52:39 +0000298
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000299 friend class ThreadManager::Impl;
Marc Slemko66949872006-07-15 01:52:39 +0000300
301 STATE _state;
302
303 bool _idle;
304};
305
Marc Slemkod466b212006-07-20 00:04:18 +0000306void ThreadManager::Impl::addWorker(size_t value) {
Marc Slemko66949872006-07-15 01:52:39 +0000307
Marc Slemko6f038a72006-08-03 18:58:09 +0000308 std::set<shared_ptr<Thread> > newThreads;
Marc Slemko66949872006-07-15 01:52:39 +0000309
Marc Slemkod466b212006-07-20 00:04:18 +0000310 for(size_t ix = 0; ix < value; ix++) {
Marc Slemko66949872006-07-15 01:52:39 +0000311
Marc Slemkod466b212006-07-20 00:04:18 +0000312 class ThreadManager::Worker;
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000313
Marc Slemko6f038a72006-08-03 18:58:09 +0000314 shared_ptr<ThreadManager::Worker> worker = shared_ptr<ThreadManager::Worker>(new ThreadManager::Worker(this));
Marc Slemko66949872006-07-15 01:52:39 +0000315
Marc Slemkod466b212006-07-20 00:04:18 +0000316 newThreads.insert(_threadFactory->newThread(worker));
Marc Slemko66949872006-07-15 01:52:39 +0000317 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000318
319 {Synchronized s(_monitor);
320
321 _workerMaxCount+= value;
322
323 _workers.insert(newThreads.begin(), newThreads.end());
324 }
Marc Slemko66949872006-07-15 01:52:39 +0000325
Marc Slemko6f038a72006-08-03 18:58:09 +0000326 for(std::set<shared_ptr<Thread> >::iterator ix = newThreads.begin(); ix != newThreads.end(); ix++) {
Marc Slemkod466b212006-07-20 00:04:18 +0000327
Marc Slemko6f038a72006-08-03 18:58:09 +0000328 shared_ptr<ThreadManager::Worker> worker = dynamic_pointer_cast<ThreadManager::Worker, Runnable>((*ix)->runnable());
Marc Slemkod466b212006-07-20 00:04:18 +0000329
330 worker->_state = ThreadManager::Worker::STARTING;
331
332 (*ix)->start();
333 }
334
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000335 {Synchronized s(_workerMonitor);
Marc Slemkod466b212006-07-20 00:04:18 +0000336
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000337 while(_workerCount != _workerMaxCount) {
338 _workerMonitor.wait();
339 }
340 }
341}
Marc Slemkod466b212006-07-20 00:04:18 +0000342
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000343void ThreadManager::Impl::start() {
344
345 if(_state == ThreadManager::STOPPED) {
346 return;
347 }
348
349 {Synchronized s(_monitor);
350
351 if(_state == ThreadManager::UNINITIALIZED) {
352
353 if(_threadFactory == NULL) {throw InvalidArgumentException();}
354
355 _state = ThreadManager::STARTED;
356
357 _monitor.notifyAll();
358 }
359
360 while(_state == STARTING) {
361
Marc Slemkod466b212006-07-20 00:04:18 +0000362 _monitor.wait();
363 }
364 }
365}
366
367void ThreadManager::Impl::stop() {
368
369 bool doStop = false;
370
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000371 if(_state == ThreadManager::STOPPED) {
372 return;
373 }
374
Marc Slemkod466b212006-07-20 00:04:18 +0000375 {Synchronized s(_monitor);
376
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000377 if(!_state != ThreadManager::STOPPING && _state != ThreadManager::STOPPED) {
378
Marc Slemkod466b212006-07-20 00:04:18 +0000379 doStop = true;
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000380
381 _state = ThreadManager::STOPPING;
Marc Slemkod466b212006-07-20 00:04:18 +0000382 }
383 }
384
385 if(doStop) {
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000386
Marc Slemkod466b212006-07-20 00:04:18 +0000387 removeWorker(_workerCount);
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000388
389 _state = ThreadManager::STOPPING;
Marc Slemkod466b212006-07-20 00:04:18 +0000390 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000391
Marc Slemko6f038a72006-08-03 18:58:09 +0000392 // XXX
393 // should be able to block here for transition to STOPPED since we're now using shared_ptrs
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000394
Marc Slemkod466b212006-07-20 00:04:18 +0000395}
396
397void ThreadManager::Impl::removeWorker(size_t value) {
Marc Slemko66949872006-07-15 01:52:39 +0000398
Marc Slemko6f038a72006-08-03 18:58:09 +0000399 std::set<shared_ptr<Thread> > removedThreads;
Marc Slemko66949872006-07-15 01:52:39 +0000400
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000401 {Synchronized s(_monitor);
Marc Slemko66949872006-07-15 01:52:39 +0000402
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000403 if(value > _workerMaxCount) {
404
405 throw InvalidArgumentException();
406 }
407
408 _workerMaxCount-= value;
409
410 if(_idleCount < value) {
Marc Slemko66949872006-07-15 01:52:39 +0000411
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000412 for(size_t ix = 0; ix < _idleCount; ix++) {
Marc Slemko66949872006-07-15 01:52:39 +0000413
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000414 _monitor.notify();
Marc Slemko66949872006-07-15 01:52:39 +0000415 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000416 } else {
417
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000418 _monitor.notifyAll();
Marc Slemko66949872006-07-15 01:52:39 +0000419 }
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000420 }
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000421
422 {Synchronized s(_workerMonitor);
423
424 while(_workerCount != _workerMaxCount) {
425 _workerMonitor.wait();
426 }
427
Marc Slemko6f038a72006-08-03 18:58:09 +0000428 for(std::set<shared_ptr<Thread> >::iterator ix = _deadWorkers.begin(); ix != _deadWorkers.end(); ix++) {
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000429
430 _workers.erase(*ix);
431
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000432 }
433
434 _deadWorkers.clear();
435 }
436}
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000437
Marc Slemko6f038a72006-08-03 18:58:09 +0000438void ThreadManager::Impl::add(shared_ptr<Runnable> value) {
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000439
440 Synchronized s(_monitor);
441
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000442 if(_state != ThreadManager::STARTED) {
443
444 throw IllegalStateException();
445 }
Marc Slemkod466b212006-07-20 00:04:18 +0000446
Marc Slemko6f038a72006-08-03 18:58:09 +0000447 _tasks.push(shared_ptr<ThreadManager::Task>(new ThreadManager::Task(value)));
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000448
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000449 /* If idle thread is available notify it, otherwise all worker threads are running and will get around to this
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000450 task in time. */
451
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000452 if(_idleCount > 0) {
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000453
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000454 _monitor.notify();
455 }
Marc Slemko66949872006-07-15 01:52:39 +0000456 }
457
Marc Slemko6f038a72006-08-03 18:58:09 +0000458void ThreadManager::Impl::remove(shared_ptr<Runnable> task) {
Marc Slemko66949872006-07-15 01:52:39 +0000459
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000460 Synchronized s(_monitor);
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000461
462 if(_state != ThreadManager::STARTED) {
463
464 throw IllegalStateException();
465 }
Marc Slemko66949872006-07-15 01:52:39 +0000466}
467
Marc Slemkod466b212006-07-20 00:04:18 +0000468class SimpleThreadManager : public ThreadManager::Impl {
Marc Slemko66949872006-07-15 01:52:39 +0000469
Marc Slemkod466b212006-07-20 00:04:18 +0000470public:
Marc Slemko66949872006-07-15 01:52:39 +0000471
Marc Slemkod466b212006-07-20 00:04:18 +0000472 SimpleThreadManager(size_t workerCount=4) :
473 _workerCount(workerCount),
474 _firstTime(true) {
475 }
Marc Slemko66949872006-07-15 01:52:39 +0000476
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000477 void start() {
478 ThreadManager::Impl::start();
Marc Slemko66949872006-07-15 01:52:39 +0000479
Marc Slemkofe5ba12e2006-07-20 21:16:27 +0000480 addWorker(_workerCount);
Marc Slemkod466b212006-07-20 00:04:18 +0000481 }
482
483private:
484
485 const size_t _workerCount;
486 bool _firstTime;
487 Monitor _monitor;
Marc Slemko0e53ccd2006-07-17 23:51:05 +0000488};
Marc Slemko66949872006-07-15 01:52:39 +0000489
Marc Slemko66949872006-07-15 01:52:39 +0000490
Marc Slemko6f038a72006-08-03 18:58:09 +0000491shared_ptr<ThreadManager> ThreadManager::newThreadManager() {
492 return shared_ptr<ThreadManager>(new ThreadManager::Impl());
Marc Slemkod466b212006-07-20 00:04:18 +0000493}
Marc Slemko66949872006-07-15 01:52:39 +0000494
Marc Slemko6f038a72006-08-03 18:58:09 +0000495shared_ptr<ThreadManager> ThreadManager::newSimpleThreadManager(size_t count) {
496 return shared_ptr<ThreadManager>(new SimpleThreadManager(count));
Marc Slemkod466b212006-07-20 00:04:18 +0000497}
Marc Slemko66949872006-07-15 01:52:39 +0000498
499}}} // facebook::thrift::concurrency
500