aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/utils/SkThreadPool.cpp
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-10-31 15:52:16 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-10-31 15:52:16 +0000
commit4177ef4b229b5fb67f355569654981bb4bf8eb9c (patch)
tree0091c5ff6ed7dd7b89e73f9b11cde51e700c5726 /src/utils/SkThreadPool.cpp
parent72ba668db833d25ecdca4edfbefd601e508a1e62 (diff)
Add SkThreadPool for managing threads.
Skia-ized from https://codereview.appspot.com/6755043/ TODO: Use SkThread and platform independent features. Review URL: https://codereview.appspot.com/6777064 git-svn-id: http://skia.googlecode.com/svn/trunk@6217 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/utils/SkThreadPool.cpp')
-rw-r--r--src/utils/SkThreadPool.cpp88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/utils/SkThreadPool.cpp b/src/utils/SkThreadPool.cpp
new file mode 100644
index 0000000000..78cb417d07
--- /dev/null
+++ b/src/utils/SkThreadPool.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkThreadPool.h"
+#include "SkRunnable.h"
+#include "SkThreadUtils.h"
+
+SkThreadPool::SkThreadPool(const int count)
+: fDone(false) {
+ // Create count threads, all running SkThreadPool::Loop.
+ for (int i = 0; i < count; i++) {
+ SkThread* thread = SkNEW_ARGS(SkThread, (&SkThreadPool::Loop, this));
+ *fThreads.append() = thread;
+ thread->start();
+ }
+}
+
+SkThreadPool::~SkThreadPool() {
+ fDone = true;
+ fReady.lock();
+ fReady.broadcast();
+ fReady.unlock();
+
+ // Wait for all threads to stop.
+ for (int i = 0; i < fThreads.count(); i++) {
+ fThreads[i]->join();
+ SkDELETE(fThreads[i]);
+ }
+}
+
+/*static*/ void SkThreadPool::Loop(void* arg) {
+ // The SkThreadPool passes itself as arg to each thread as they're created.
+ SkThreadPool* pool = static_cast<SkThreadPool*>(arg);
+
+ while (true) {
+ // We have to be holding the lock to read the queue and to call wait.
+ pool->fReady.lock();
+ while(pool->fQueue.isEmpty()) {
+ // Is it time to die?
+ if (pool->fDone) {
+ pool->fReady.unlock();
+ return;
+ }
+ // wait yields the lock while waiting, but will have it again when awoken.
+ pool->fReady.wait();
+ }
+ // We've got the lock back here, no matter if we ran wait or not.
+
+ // The queue is not empty, so we have something to run. Claim it.
+ LinkedRunnable* r = pool->fQueue.tail();
+
+ pool->fQueue.remove(r);
+
+ // Having claimed our SkRunnable, we now give up the lock while we run it.
+ // Otherwise, we'd only ever do work on one thread at a time, which rather
+ // defeats the point of this code.
+ pool->fReady.unlock();
+
+ // OK, now really do the work.
+ r->fRunnable->run();
+ SkDELETE(r);
+ }
+
+ SkASSERT(false); // Unreachable. The only exit happens when pool->fDone.
+}
+
+void SkThreadPool::add(SkRunnable* r) {
+ if (NULL == r) {
+ return;
+ }
+
+ // If we don't have any threads, obligingly just run the thing now.
+ if (fThreads.isEmpty()) {
+ return r->run();
+ }
+
+ // We have some threads. Queue it up!
+ fReady.lock();
+ LinkedRunnable* linkedRunnable = SkNEW(LinkedRunnable);
+ linkedRunnable->fRunnable = r;
+ fQueue.addToHead(linkedRunnable);
+ fReady.signal();
+ fReady.unlock();
+}