00001
00002
00003
00004
00005
00006
00007
00008
00009 static const char rcsid[] __attribute__((used)) = "$Id: ThreadPool.cpp 1230 2014-11-16 02:32:01Z sella $";
00010
00011 #include "ThreadPool.h"
00012 #include "CommonMacro.h"
00013 #include "Time.h"
00014
00015 #include <stdio.h>
00016 #include <assert.h>
00017 #include <stdlib.h>
00018 #include <unistd.h>
00019 #include <sys/time.h>
00020 #include <syscall.h>
00021
00022 #include <algorithm>
00023
00024 using namespace sella::util;
00025 using namespace std::chrono;
00026
00027 ThreadPool::ThreadPool(size_t workers) :
00028 TaskQueue(workers * 2),
00029 threads(0),
00030 creating(0),
00031 actives(0),
00032 overage(0),
00033 shutdown(false),
00034 paused(false),
00035 allcpus(true),
00036 maximum(workers),
00037 minimum(workers),
00038 spares(DefaultSpareWorkers)
00039 {
00040 clearCPUAffinity();
00041 normalize();
00042
00043 TRACE(PACKAGE, "ThreadPool starting up with %zd workers", this->maximum);
00044
00045 managerTID = std::thread(&ThreadPool::manager, this);
00046 tids.insert(managerTID.native_handle());
00047 }
00048
00049 ThreadPool::ThreadPool(size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers) :
00050 TaskQueue(maximumWorkers * 2),
00051 threads(0),
00052 creating(0),
00053 actives(0),
00054 overage(0),
00055 shutdown(false),
00056 paused(false),
00057 allcpus(true),
00058 maximum(maximumWorkers),
00059 minimum(minimumWorkers),
00060 spares(spareWorkers)
00061 {
00062 clearCPUAffinity();
00063 normalize();
00064
00065 TRACE(PACKAGE, "ThreadPool starting up with %zd/%zd workers, %zd spares", this->minimum, this->maximum, this->spares);
00066
00067 managerTID = std::thread(&ThreadPool::manager, this);
00068 tids.insert(managerTID.native_handle());
00069 }
00070
00071 ThreadPool::ThreadPool(Log::shared log, size_t workers) :
00072 TaskQueue(log, workers * 2),
00073 threads(0),
00074 creating(0),
00075 actives(0),
00076 overage(0),
00077 shutdown(false),
00078 paused(false),
00079 allcpus(true),
00080 maximum(workers),
00081 minimum(workers),
00082 spares(DefaultSpareWorkers)
00083 {
00084 clearCPUAffinity();
00085 normalize();
00086
00087 TRACE(PACKAGE, "ThreadPool starting up with %zd workers", this->maximum);
00088
00089 managerTID = std::thread(&ThreadPool::manager, this);
00090 tids.insert(managerTID.native_handle());
00091 }
00092
00093 ThreadPool::ThreadPool(Log::shared log, size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers) :
00094 TaskQueue(log, maximumWorkers * 2),
00095 threads(0),
00096 creating(0),
00097 actives(0),
00098 overage(0),
00099 shutdown(false),
00100 paused(false),
00101 allcpus(true),
00102 maximum(maximumWorkers),
00103 minimum(minimumWorkers),
00104 spares(spareWorkers)
00105 {
00106 clearCPUAffinity();
00107 normalize();
00108
00109 TRACE(PACKAGE, "ThreadPool starting up with %zd/%zd workers, %zd spares", this->minimum, this->maximum, this->spares);
00110
00111 managerTID = std::thread(&ThreadPool::manager, this);
00112 tids.insert(managerTID.native_handle());
00113 }
00114
00115 ThreadPool::~ThreadPool() {
00116 TRACE(PACKAGE, "ThreadPool shutting down with %zd queued, %zd workers, %zd active", heap.size(), (size_t) threads, (size_t) actives);
00117
00118 shutdown = true;
00119 managerMutex.lock();
00120 managerCV.notify_all();
00121 managerMutex.unlock();
00122
00123 if (managerTID.joinable()) {
00124 managerTID.join();
00125 }
00126
00127 std::lock_guard<std::mutex> lg(emptyMutex);
00128 emptyCV.notify_all();
00129 }
00130
00131 void ThreadPool::schedule(Task::shared &task, int priority) {
00132 assert(task.get() != NULL);
00133
00134 if (priority) task->setPriority(priority);
00135
00136 TRACE(PACKAGE "-detail", "Scheduling task %p to run immedately with priority %d", task.get(), task->getPriority());
00137
00138 heapMutex.lock();
00139 push(task);
00140 heapMutex.unlock();
00141
00142 std::lock_guard<std::mutex> lg(managerMutex);
00143 managerCV.notify_all();
00144 }
00145
00146 void ThreadPool::schedule(Task::shared &task, const std::chrono::system_clock::duration &delay, int priority) {
00147 assert(task.get() != NULL);
00148
00149 task->setDelay(delay);
00150 if (priority) task->setPriority(priority);
00151
00152 TRACE(PACKAGE "-detail", "Scheduling task %p to run in %lld.%lld sec with priority %d", task.get(), task->getDelay().tv_sec, task->getDelay().tv_usec, task->getPriority());
00153
00154 heapMutex.lock();
00155 push(task);
00156 heapMutex.unlock();
00157
00158 std::lock_guard<std::mutex> lg(managerMutex);
00159 managerCV.notify_all();
00160 }
00161
00162 void ThreadPool::schedule(Task::shared &task, const std::chrono::system_clock::time_point &time, int priority) {
00163 assert(task.get() != NULL);
00164
00165 task->setTimer(time);
00166 if (priority) task->setPriority(priority);
00167
00168 TRACE(PACKAGE "-detail", "Scheduling task %p to run at %lld.%lld sec with priority %d", task.get(), task->getTimer().tv_sec, task->getTimer().tv_usec, task->getPriority());
00169
00170 heapMutex.lock();
00171 push(task);
00172 heapMutex.unlock();
00173
00174 std::lock_guard<std::mutex> lg(managerMutex);
00175 managerCV.notify_all();
00176 }
00177
00178 void ThreadPool::schedule(Task::shared &task, time_t sec, suseconds_t usec, int priority) {
00179 assert(task.get() != NULL);
00180
00181 task->setDelay(sec, usec);
00182 if (priority) task->setPriority(priority);
00183
00184 TRACE(PACKAGE "-detail", "Scheduling task %p to run in %lld.%lld sec with priority %d", task.get(), sec, usec, task->getPriority());
00185
00186 heapMutex.lock();
00187 push(task);
00188 heapMutex.unlock();
00189
00190 std::lock_guard<std::mutex> lg(managerMutex);
00191 managerCV.notify_all();
00192 }
00193
00194 void ThreadPool::schedule(Task::shared &task, timeval &tv, int priority) {
00195 assert(task.get() != NULL);
00196
00197 task->setTimer(tv);
00198 if (priority) task->setPriority(priority);
00199
00200 TRACE(PACKAGE "-detail", "Scheduling task %p to run at %lld.%lld sec with priority %d", task.get(), Time::tvtosec(tv), Time::tvtousec(tv), task->getPriority());
00201
00202 heapMutex.lock();
00203 push(task);
00204 heapMutex.unlock();
00205
00206 std::lock_guard<std::mutex> lg(managerMutex);
00207 managerCV.notify_all();
00208 }
00209
00210 bool ThreadPool::reschedule(Task::shared &task, const std::chrono::system_clock::duration &delay, int priority, bool strict) {
00211 assert(task.get() != NULL);
00212
00213 task->setDelay(delay);
00214 if (priority) task->setPriority(priority);
00215
00216 TRACE(PACKAGE "-detail", "Rescheduling task %p to run in %lld.%lld sec with priority %d", task.get(), task->getDelay().tv_sec, task->getDelay().tv_usec, task->getPriority());
00217
00218 heapMutex.lock();
00219 bool res = repush(task, delay, priority, strict);
00220 heapMutex.unlock();
00221
00222 std::lock_guard<std::mutex> lg(managerMutex);
00223 managerCV.notify_all();
00224
00225 return res;
00226 }
00227
00228 bool ThreadPool::reschedule(Task::shared &task, const std::chrono::system_clock::time_point &time, int priority, bool strict) {
00229 assert(task.get() != NULL);
00230
00231 task->setTimer(time);
00232 if (priority) task->setPriority(priority);
00233
00234 TRACE(PACKAGE "-detail", "Rescheduling task %p to run at %lld.%lld sec with priority %d", task.get(), task->getTimer().tv_sec, task->getTimer().tv_usec, task->getPriority());
00235
00236 heapMutex.lock();
00237 bool res = repush(task, time, priority, strict);
00238 heapMutex.unlock();
00239
00240 std::lock_guard<std::mutex> lg(managerMutex);
00241 managerCV.notify_all();
00242
00243 return res;
00244 }
00245
00246 bool ThreadPool::reschedule(Task::shared &task, time_t sec, suseconds_t usec, int priority, bool strict) {
00247 assert(task.get() != NULL);
00248
00249 if (priority) task->setPriority(priority);
00250
00251 TRACE(PACKAGE "-detail", "Rescheduling task %p to run in %lld.%lld sec with priority %d", task.get(), sec, usec, task->getPriority());
00252
00253 heapMutex.lock();
00254 bool res = repush(task, sec, usec, priority, strict);
00255 heapMutex.unlock();
00256
00257 std::lock_guard<std::mutex> lg(managerMutex);
00258 managerCV.notify_all();
00259
00260 return res;
00261 }
00262
00263 bool ThreadPool::reschedule(Task::shared &task, timeval &tv, int priority, bool strict) {
00264 assert(task.get() != NULL);
00265
00266 if (priority) task->setPriority(priority);
00267
00268 TRACE(PACKAGE "-detail", "Rescheduling task %p to run at %lld.%lld sec with priority %d", task.get(), tv.tv_sec, tv.tv_usec, task->getPriority());
00269
00270 heapMutex.lock();
00271 bool res = repush(task, tv, priority, strict);
00272 heapMutex.unlock();
00273
00274 std::lock_guard<std::mutex> lg(managerMutex);
00275 managerCV.notify_all();
00276
00277 return res;
00278 }
00279
00280 bool ThreadPool::unschedule(Task::shared &task, bool firstonly) {
00281 TRACE(PACKAGE "-detail", "Unscheduling task %p%s", task.get(), (firstonly) ? " (firstonly)" : "");
00282
00283 heapMutex.lock();
00284 bool res = erase(task, firstonly);
00285 heapMutex.unlock();
00286
00287 std::lock_guard<std::mutex> lg(managerMutex);
00288 managerCV.notify_all();
00289
00290 return res;
00291 }
00292
00293 void ThreadPool::pause(bool on) {
00294 std::lock_guard<std::mutex> lg(managerMutex);
00295
00296 if ((paused = on) == false) {
00297 TRACE(PACKAGE, "Resuming %zd queued, %zd workers, %zd active", heap.size(), (size_t) threads, (size_t) actives);
00298
00299 managerCV.notify_all();
00300 } else {
00301 TRACE(PACKAGE, "Pausing %zd queued, %zd workers, %zd active", heap.size(), (size_t) threads, (size_t) actives);
00302 }
00303 }
00304
00305 size_t ThreadPool::getCPUCount(void) {
00306 return (std::thread::hardware_concurrency() > 0) ? std::thread::hardware_concurrency() : sysconf(_SC_NPROCESSORS_ONLN);
00307 }
00308
00309 int ThreadPool::getCPUSetCount(void) {
00310 return CPU_COUNT(&cpuset);
00311 }
00312
00313 bool ThreadPool::addCPUAffinity(std::set<int> cpus) {
00314 size_t count = getCPUCount();
00315
00316 if (allcpus) {
00317 CPU_ZERO(&cpuset);
00318 }
00319
00320 for (auto c = cpus.begin(); c != cpus.end(); ++c) {
00321 if ((size_t) *c < count) {
00322 CPU_SET(*c, &cpuset);
00323 }
00324 }
00325
00326 if (CPU_COUNT(&cpuset) == 0) {
00327 clearCPUAffinity();
00328 } else {
00329 allcpus = false;
00330 }
00331
00332 return setThreadsAffinity();
00333 }
00334
00335 bool ThreadPool::addCPUAffinity(int cpu) {
00336 size_t count = getCPUCount();
00337
00338 if (allcpus) {
00339 CPU_ZERO(&cpuset);
00340 }
00341
00342 if ((size_t) cpu < count) {
00343 CPU_SET(cpu, &cpuset);
00344 }
00345
00346 if (CPU_COUNT(&cpuset) == 0) {
00347 clearCPUAffinity();
00348 } else {
00349 allcpus = false;
00350 }
00351
00352 return setThreadsAffinity();
00353 }
00354
00355 bool ThreadPool::clearCPUAffinity(void) {
00356 CPU_ZERO(&cpuset);
00357 allcpus = true;
00358
00359 size_t cpus = getCPUCount();
00360
00361 for (size_t i = 0; i < cpus; i++) {
00362 CPU_SET(i, &cpuset);
00363 }
00364
00365 return setThreadsAffinity();
00366 }
00367
00368 bool ThreadPool::clearCPUAffinity(int cpu) {
00369 if (cpu < CPU_SETSIZE) {
00370 CPU_CLR(cpu, &cpuset);
00371 }
00372
00373 if (CPU_COUNT(&cpuset) == 0) {
00374 clearCPUAffinity();
00375 }
00376
00377 return setThreadsAffinity();
00378 }
00379
00380 bool ThreadPool::clearCPUAffinity(std::set<int> cpus) {
00381 for (auto c = cpus.begin(); c != cpus.end(); ++c) {
00382 if (*c < CPU_SETSIZE) {
00383 CPU_CLR(*c, &cpuset);
00384 }
00385 }
00386
00387 if (CPU_COUNT(&cpuset) == 0) {
00388 clearCPUAffinity();
00389 }
00390
00391 return setThreadsAffinity();
00392 }
00393
00394 size_t ThreadPool::size(void) const {
00395 std::lock_guard<std::mutex> lg(heapMutex);
00396
00397 if (!TaskQueue::empty()) {
00398 Task::shared task = top();
00399 timeval delay = task->getDelay();
00400 }
00401
00402 return TaskQueue::size() + actives;
00403 }
00404
00405 size_t ThreadPool::workers(void) const {
00406 return threads;
00407 }
00408
00409 size_t ThreadPool::active(void) const {
00410 return actives;
00411 }
00412
00413 bool ThreadPool::empty(void) const {
00414 return (size() == 0);
00415 }
00416
00417 void ThreadPool::clear(void) {
00418 heapMutex.lock();
00419 TaskQueue::clear();
00420 heapMutex.unlock();
00421
00422 std::lock_guard<std::mutex> lg(managerMutex);
00423 managerCV.notify_all();
00424 }
00425
00426 Task::shared ThreadPool::next(void) {
00427 std::lock_guard<std::mutex> lg(heapMutex);
00428
00429 if (!TaskQueue::empty()) {
00430 Task::shared task = top();
00431
00432 if (task && Task::compareTimer(task)) {
00433 pop();
00434
00435 return task;
00436 }
00437 }
00438
00439 return Task::shared();
00440 }
00441
00442 microseconds ThreadPool::duration(void) const {
00443 if (actives == maximum || UNLIKELY(paused && !shutdown)) {
00444 return max();
00445 }
00446
00447 std::lock_guard<std::mutex> lg(heapMutex);
00448
00449 if (!TaskQueue::empty()) {
00450 Task::shared task = top();
00451 timeval delay = task->getDelay();
00452
00453 if (delay.tv_usec < 1 && delay.tv_sec < 1) {
00454 if (creating) {
00455 return milliseconds(10);
00456 } else {
00457 return milliseconds(2);
00458 }
00459 }
00460
00461 return seconds(delay.tv_sec) + microseconds(delay.tv_usec);
00462 } else if (UNLIKELY(shutdown)) {
00463 return milliseconds(1);
00464 }
00465
00466 return max();
00467 }
00468
00469 microseconds ThreadPool::max(void) const {
00470 return hours(24 * 365 * 100);
00471 }
00472
00473 bool ThreadPool::ready(void) const {
00474 if (TaskQueue::empty()) {
00475 return false;
00476 }
00477
00478 std::lock_guard<std::mutex> lg(heapMutex);
00479
00480 return Task::compareTimer(top());
00481 }
00482
00483 bool ThreadPool::wait(void) {
00484 std::unique_lock<std::mutex> lock(emptyMutex);
00485
00486 if (empty()) {
00487 managerMutex.lock();
00488 managerCV.notify_all();
00489 managerMutex.unlock();
00490
00491 return true;
00492 }
00493
00494 managerMutex.lock();
00495 managerCV.notify_all();
00496 managerMutex.unlock();
00497
00498 emptyCV.wait(lock);
00499
00500 return empty();
00501 }
00502
00503 bool ThreadPool::wait(const std::chrono::system_clock::duration &delay) {
00504 std::unique_lock<std::mutex> lock(emptyMutex);
00505
00506 if (empty()) {
00507 managerMutex.lock();
00508 managerCV.notify_all();
00509 managerMutex.unlock();
00510
00511 return true;
00512 }
00513
00514 managerMutex.lock();
00515 managerCV.notify_all();
00516 managerMutex.unlock();
00517
00518 emptyCV.wait_for(lock, delay);
00519
00520 return empty();
00521 }
00522
00523 bool ThreadPool::wait(const std::chrono::system_clock::time_point &time) {
00524 std::unique_lock<std::mutex> lock(emptyMutex);
00525
00526 if (empty()) {
00527 managerMutex.lock();
00528 managerCV.notify_all();
00529 managerMutex.unlock();
00530
00531 return true;
00532 }
00533
00534 managerMutex.lock();
00535 managerCV.notify_all();
00536 managerMutex.unlock();
00537
00538 emptyCV.wait_until(lock, time);
00539
00540 return empty();
00541 }
00542
00543 void ThreadPool::reserve(size_t capacity) {
00544 std::lock_guard<std::mutex> lg(heapMutex);
00545 TaskQueue::reserve(capacity);
00546 }
00547
00548 void ThreadPool::print(void) const {
00549 std::lock_guard<std::mutex> lg(heapMutex);
00550
00551 Task::shared task;
00552 timeval now, timer, delay;
00553
00554 if (libutilxx__log == NULL) {
00555 return;
00556 }
00557
00558 gettimeofday(&now, NULL);
00559 INFO("[ThreadPool Heap] - now %10lu.%06lu, %zd, queued, %zd workers, %zd active, %zd overage", now.tv_sec, now.tv_usec, heap.size(), (size_t) threads, (size_t) actives, (size_t) overage);
00560
00561 if (heap.empty()) {
00562 INFO(" heap => empty");
00563
00564 return;
00565 }
00566
00567 for (auto it = heap.begin(); it != heap.end(); ++it) {
00568 timer = (*it)->getTimer();
00569 if (timerisset(&timer)) {
00570
00571 delay.tv_sec = timer.tv_sec - now.tv_sec;
00572 delay.tv_usec = timer.tv_usec - now.tv_usec;
00573 if (delay.tv_sec > 0 && delay.tv_usec < 0) {
00574 --delay.tv_sec;
00575 delay.tv_usec += 1000000;
00576 }
00577
00578 INFO(" heap => task(%10p) obj: %10p pri: %3d timer: %10lu.%06lu delay: %4d.%d", (*it).get(), (*it)->getObject(), (*it)->getPriority(), timer.tv_sec, timer.tv_usec, (signed) delay.tv_sec, (signed) delay.tv_usec);
00579 } else {
00580 INFO(" heap => task(%10p) obj: %10p pri: %3d timer: %10lu.%06lu delay: -inf", (*it).get(), (*it)->getObject(), (*it)->getPriority(), timer.tv_sec, timer.tv_usec);
00581 }
00582 }
00583 }
00584
00585 ThreadPool::shared ThreadPool::shared_ptr(size_t maximumWorkers) {
00586 return std::make_shared<ThreadPool>(maximumWorkers);
00587 }
00588
00589 ThreadPool::shared ThreadPool::shared_ptr(size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers) {
00590 return std::make_shared<ThreadPool>(maximumWorkers, minimumWorkers, spareWorkers);
00591 }
00592
00593 ThreadPool::shared ThreadPool::shared_ptr(Log::shared log, size_t maximumWorkers) {
00594 return std::make_shared<ThreadPool>(log, maximumWorkers);
00595 }
00596
00597 ThreadPool::shared ThreadPool::shared_ptr(Log::shared log, size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers) {
00598 return std::make_shared<ThreadPool>(log, maximumWorkers, minimumWorkers, spareWorkers);
00599 }
00600
00601 void ThreadPool::manager(void) {
00602 size_t cycles = 0;
00603
00604 for (size_t i = 0; !shutdown && i < minimum; i++) {
00605 createWorker();
00606 }
00607
00608 TRACE(PACKAGE "-detail", "Manager started up with %zd threads", (size_t) threads);
00609
00610 while (LIKELY(!shutdown)) {
00611 if (minimum == maximum) {
00612 while (LIKELY(!shutdown) && threads < minimum) {
00613 createWorker();
00614 }
00615 } else {
00616 while (LIKELY(!shutdown) && threads < maximum && threads < actives + spares) {
00617 createWorker();
00618 }
00619
00620 if (ready() || (++cycles % maximum) != 0) {
00621 overage = 0;
00622 } else {
00623 if (threads > minimum && threads > actives + spares) {
00624 overage = threads - actives + spares;
00625 } else if (actives == 0) {
00626 overage = threads - minimum;
00627 }
00628
00629 TRACE(PACKAGE "-detail", "Manager set overage to %zd", (size_t) overage);
00630
00631 for (size_t i = 0; LIKELY(!shutdown) && i < overage && i < maximum; i++) {
00632 TRACE(PACKAGE "-detail", "Manager waking worker for overage");
00633
00634 std::lock_guard<std::mutex> lg(workerMutex);
00635 workerCV.notify_one();
00636 }
00637 }
00638 }
00639
00640 if (LIKELY(!shutdown)) {
00641 TRACE(PACKAGE, "Manager waiting for tasks - %zd queued, %zd active, %zd/%zd workers", heap.size(), (size_t) actives, (size_t) threads, maximum);
00642
00643 std::unique_lock<std::mutex> lock(managerMutex);
00644 do {
00645 emptyMutex.lock();
00646 if (empty()) {
00647 emptyCV.notify_all();
00648 }
00649 emptyMutex.unlock();
00650
00651 microseconds delay = duration();
00652 #if 0
00653 TRACE(PACKAGE "-detail", "delay: %lld, active: %zd, threads: %zd, overage: %zd, shutdown: %d", microseconds(delay).count(), (size_t) actives, (size_t) threads, (size_t) overage, shutdown);
00654 #endif
00655 managerCV.wait_for(lock, delay);
00656 } while (UNLIKELY(paused && !shutdown));
00657 }
00658
00659 if (LIKELY(!shutdown)) {
00660 size_t max = maximum - actives;
00661
00662 TRACE(PACKAGE, "Manager waking %zd worker(s) - %zd queued, %zd active, %zd/%zd workers", max, heap.size(), (size_t) actives, (size_t) threads, maximum);
00663
00664 std::lock_guard<std::mutex> lg(workerMutex);
00665 for (size_t i = 0; ready() && i < max; i++) {
00666 workerCV.notify_one();
00667 }
00668 }
00669 }
00670
00671 TRACE(PACKAGE "-detail", "Manager waiting on remaining %zd workers to complete", (size_t) threads);
00672
00673 clear();
00674 overage = (size_t) threads;
00675 workerCV.notify_all();
00676
00677 while (threads > 0) {
00678 std::unique_lock<std::mutex> lock(managerMutex);
00679 managerCV.wait_for(lock, seconds(1));
00680
00681 workerCV.notify_all();
00682 }
00683
00684 std::lock_guard<std::mutex> lg(emptyMutex);
00685 emptyCV.notify_all();
00686
00687 TRACE(PACKAGE, "Manager shutdown");
00688 }
00689
00690 void ThreadPool::worker(void) {
00691 Task::shared task;
00692 int tid = syscall(SYS_gettid);
00693
00694 TRACE(PACKAGE, "Worker(%d) started", tid);
00695
00696 actives++;
00697 creating--;
00698
00699 while (LIKELY(!shutdown)) {
00700 {
00701 TRACE(PACKAGE "-detail", "Worker(%d) waiting for next task", tid);
00702
00703 std::unique_lock<std::mutex> lock(workerMutex);
00704
00705 managerMutex.lock();
00706 managerCV.notify_all();
00707 managerMutex.unlock();
00708
00709 --actives;
00710 workerCV.wait(lock);
00711 ++actives;
00712 }
00713
00714 if (LIKELY(!shutdown)) {
00715 if (overage) {
00716 std::lock_guard<std::mutex> lg(overageMutex);
00717
00718 if (overage) {
00719 TRACE(PACKAGE "-detail", "Worker(%d) yielding up the ghost (spare worker)", tid);
00720
00721 --overage;
00722
00723 break;
00724 }
00725 }
00726
00727 workerMutex.lock();
00728
00729 if (ready()) {
00730 task = next();
00731
00732 TRACE(PACKAGE "-detail", "Worker(%d) acquired task %p with priority %d", tid, task.get(), task->getPriority());
00733 }
00734
00735 workerMutex.unlock();
00736
00737 if (task) {
00738 TRACE(PACKAGE, "Worker(%d) executing task %p with priority %d", tid, task.get(), task->getPriority());
00739
00740 task->execute();
00741 task.reset();
00742 }
00743 }
00744 }
00745
00746 TRACE(PACKAGE, "Worker(%d) ended", tid);
00747
00748 tidsMutex.lock();
00749 tids.erase(pthread_self());
00750 tidsMutex.unlock();
00751
00752 --actives;
00753 --threads;
00754
00755 std::lock_guard<std::mutex> lg(managerMutex);
00756 managerCV.notify_all();
00757 }
00758
00759 void ThreadPool::normalize(void) {
00760 if (maximum == 0) {
00761 maximum = getCPUCount();
00762 }
00763
00764 if (minimum == 0) {
00765 minimum = getCPUCount();
00766 }
00767
00768 if (spares == 0) {
00769 spares = DefaultSpareWorkers;
00770 }
00771
00772 if (minimum > maximum) {
00773 maximum = minimum;
00774 spares = 0;
00775 } else if (maximum == minimum) {
00776 spares = 0;
00777 }
00778 }
00779
00780 void ThreadPool::createWorker(void) {
00781 TRACE(PACKAGE "-detail", "Manager starting up worker %zd/%zd with affinity to %d CPUs", (size_t) threads + 1, maximum, getCPUSetCount());
00782
00783 std::thread t(&ThreadPool::worker, this);
00784 setThreadAffinity(t.native_handle());
00785
00786 tidsMutex.lock();
00787 tids.insert(t.native_handle());
00788 tidsMutex.unlock();
00789
00790 ++threads;
00791 ++creating;
00792 t.detach();
00793 }
00794
00795 bool ThreadPool::setThreadsAffinity() {
00796 std::lock_guard<std::mutex> lg(tidsMutex);
00797
00798 TRACE(PACKAGE "-detail", "Setting %zd threads affinity to %d CPUs", tids.size(), getCPUSetCount());
00799
00800 for (auto t = tids.begin(); t != tids.end(); ++t) {
00801 if (!setThreadAffinity(*t)) {
00802 return false;
00803 }
00804 }
00805
00806 return true;
00807 }
00808
00809 bool ThreadPool::setThreadAffinity(pthread_t tid) {
00810 int error;
00811
00812 if ((error = pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpuset)) != 0) {
00813 char buf[1024] = "message unavailable";
00814 strerror_r(error, buf, sizeof(buf));
00815
00816 TRACE(PACKAGE, "pthread_setaffinity_np: %d:%s", error, buf);
00817
00818 return false;
00819 }
00820
00821 return true;
00822 }
00823
00824
00825
00826