aboutsummaryrefslogtreecommitdiff
path: root/dep/g3dlite/include/G3D/GThread.h
diff options
context:
space:
mode:
Diffstat (limited to 'dep/g3dlite/include/G3D/GThread.h')
-rw-r--r--dep/g3dlite/include/G3D/GThread.h177
1 files changed, 163 insertions, 14 deletions
diff --git a/dep/g3dlite/include/G3D/GThread.h b/dep/g3dlite/include/G3D/GThread.h
index 58437efc3fb..8670fef4e76 100644
--- a/dep/g3dlite/include/G3D/GThread.h
+++ b/dep/g3dlite/include/G3D/GThread.h
@@ -2,18 +2,21 @@
@file GThread.h
@created 2005-09-22
- @edited 2007-01-31
+ @edited 2010-09-10
*/
-#ifndef G3D_GTHREAD_H
-#define G3D_GTHREAD_H
+#ifndef G3D_GThread_h
+#define G3D_GThread_h
#include "G3D/platform.h"
#include "G3D/ReferenceCount.h"
+#include "G3D/ThreadSet.h"
+#include "G3D/Vector2int32.h"
+#include "G3D/SpawnBehavior.h"
#include <string>
-#ifndef G3D_WIN32
+#ifndef G3D_WINDOWS
# include <pthread.h>
# include <signal.h>
#endif
@@ -21,7 +24,9 @@
namespace G3D {
-typedef ReferenceCountedPointer<class GThread> GThreadRef;
+typedef shared_ptr<class GThread> GThreadRef;
+
+
/**
Platform independent thread implementation. You can either subclass and
@@ -32,11 +37,11 @@ typedef ReferenceCountedPointer<class GThread> GThreadRef;
dropping all pointers (and causing deallocation) of a GThread does NOT
stop the underlying process.
- @sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32
+ \sa G3D::GMutex, G3D::Spinlock, G3D::AtomicInt32, G3D::ThreadSet
*/
class GThread : public ReferenceCountedObject {
private:
- // "Status" is a reserved work on FreeBSD
+ // "Status" is a reserved word on FreeBSD
enum GStatus {STATUS_CREATED, STATUS_STARTED, STATUS_RUNNING, STATUS_COMPLETED};
// Not implemented on purpose, don't use
@@ -44,21 +49,21 @@ private:
GThread& operator=(const GThread&);
bool operator==(const GThread&);
-#ifdef G3D_WIN32
+#ifdef G3D_WINDOWS
static DWORD WINAPI internalThreadProc(LPVOID param);
#else
static void* internalThreadProc(void* param);
-#endif //G3D_WIN32
+#endif //G3D_WINDOWS
volatile GStatus m_status;
// Thread handle to hold HANDLE and pthread_t
-#ifdef G3D_WIN32
+#ifdef G3D_WINDOWS
HANDLE m_handle;
HANDLE m_event;
#else
pthread_t m_handle;
-#endif //G3D_WIN32
+#endif //G3D_WINDOWS
std::string m_name;
@@ -68,8 +73,11 @@ protected:
virtual void threadMain() = 0;
public:
- typedef ReferenceCountedPointer<class GThread> Ref;
- enum SpawnBehavior {USE_NEW_THREAD, USE_CURRENT_THREAD};
+
+ /** Returns System::numCores(); put here to break a dependence on System.h */
+ static int numCores();
+
+ typedef shared_ptr<class GThread> Ref;
GThread(const std::string& name);
@@ -110,12 +118,153 @@ public:
void waitForCompletion();
/** Returns thread name */
- inline const std::string& name() {
+ const std::string& name() {
return m_name;
}
+
+ /** For backwards compatibility to G3D 8.xx */
+ static const SpawnBehavior USE_CURRENT_THREAD = G3D::USE_CURRENT_THREAD;
+ /** For backwards compatibility to G3D 8.xx */
+ static const SpawnBehavior USE_NEW_THREAD = G3D::USE_NEW_THREAD;
+
+ enum {
+ /** Tells GThread::runConcurrently() and GThread::runConcurrently2D() to
+ use System::numCores() threads.*/
+ NUM_CORES = -100
+ };
+
+ /**
+ \brief Iterates over a 2D region using multiple threads and
+ blocks until all threads have completed. <p> Evaluates \a
+ object->\a method(\a x, \a y) for every <code>start.x <= x <
+ upTo.x</code> and <code>start.y <= y < upTo.y</code>.
+ Iteration is row major, so each thread can expect to see
+ successive x values. </p>
+ \param maxThreads
+ Maximum number of threads to use. By default at most one
+ thread per processor core will be used.
+
+ Example:
+
+ \code
+ class RayTracer {
+ public:
+ void trace(const Vector2int32& pixel) {
+ ...
+ }
+
+ void traceAll() {
+ GThread::runConcurrently2D(Point2int32(0,0), Point2int32(w,h), this, &RayTracer::trace);
+ }
+ };
+ \endcode
+ */
+ template<class Class>
+ static void runConcurrently2D
+ (const Vector2int32& start,
+ const Vector2int32& upTo,
+ Class* object,
+ void (Class::*method)(int x, int y),
+ int maxThreads = NUM_CORES) {
+ _internal_runConcurrently2DHelper(start, upTo, object, method, static_cast<void (Class::*)(int, int, int)>(NULL), maxThreads);
+ }
+
+ /** Like the other version of runConcurrently2D, but tells the
+ method the thread index that it is running on. That enables
+ the caller to manage per-thread state.
+ */
+ template<class Class>
+ static void runConcurrently2D
+ (const Vector2int32& start,
+ const Vector2int32& upTo,
+ Class* object,
+ void (Class::*method)(int x, int y, int threadID),
+ int maxThreads = NUM_CORES) {
+ _internal_runConcurrently2DHelper(start, upTo, object, static_cast<void (Class::*)(int, int)>(NULL), method, maxThreads);
+ }
+
};
+
+ // Can't use an inherited class inside of its parent on g++ 4.2.1 if it is later a template parameter
+
+ /** For use by runConcurrently2D. Designed for arbitrary iteration, although only used for
+ interlaced rows in the current implementation. */
+ template<class Class>
+ class _internalGThreadWorker : public GThread {
+ public:
+ /** Start for this thread, which differs from the others */
+ const int threadID;
+ const Vector2int32 start;
+ const Vector2int32 upTo;
+ const Vector2int32 stride;
+ Class* object;
+ void (Class::*method1)(int x, int y);
+ void (Class::*method2)(int x, int y, int threadID);
+
+ _internalGThreadWorker(int threadID,
+ const Vector2int32& start,
+ const Vector2int32& upTo,
+ Class* object,
+ void (Class::*method1)(int x, int y),
+ void (Class::*method2)(int x, int y, int threadID),
+ const Vector2int32& stride) :
+ GThread("runConcurrently2D worker"),
+ threadID(threadID),
+ start(start),
+ upTo(upTo),
+ stride(stride),
+ object(object),
+ method1(method1),
+ method2(method2) {}
+
+ virtual void threadMain() {
+ for (int y = start.y; y < upTo.y; y += stride.y) {
+ // Run whichever method was provided
+ if (method1) {
+ for (int x = start.x; x < upTo.x; x += stride.x) {
+ (object->*method1)(x, y);
+ }
+ } else {
+ for (int x = start.x; x < upTo.x; x += stride.x) {
+ (object->*method2)(x, y, threadID);
+ }
+ }
+ }
+ }
+ };
+
+
+ template<class Class>
+ void _internal_runConcurrently2DHelper
+ (const Vector2int32& start,
+ const Vector2int32& upTo,
+ Class* object,
+ void (Class::*method1)(int x, int y),
+ void (Class::*method2)(int x, int y, int threadID),
+ int maxThreads) {
+
+ // Create a group of threads
+ if (maxThreads == GThread::NUM_CORES) {
+ maxThreads = GThread::numCores();
+ }
+
+ const int numRows = upTo.y - start.y;
+ const int numThreads = min(maxThreads, numRows);
+ const Vector2int32 stride(1, numThreads);
+ ThreadSet threadSet;
+ for (int t = 0; t < numThreads; ++t) {
+ threadSet.insert(shared_ptr<_internalGThreadWorker<Class> >(new _internalGThreadWorker<Class>(t, start + Vector2int32(0, t), upTo, object, method1, method2, stride)));
+ }
+
+ // Run the threads, reusing the current thread and blocking until
+ // all complete
+ threadSet.start(USE_CURRENT_THREAD);
+ threadSet.waitForCompletion();
+ }
+
+
} // namespace G3D
#endif //G3D_GTHREAD_H