diff options
Diffstat (limited to 'src/Common')
-rw-r--r-- | src/Common/ThreadManager.cpp | 52 | ||||
-rw-r--r-- | src/Common/ThreadManager.h | 21 |
2 files changed, 66 insertions, 7 deletions
diff --git a/src/Common/ThreadManager.cpp b/src/Common/ThreadManager.cpp index 6b2606c..c0f4d74 100644 --- a/src/Common/ThreadManager.cpp +++ b/src/Common/ThreadManager.cpp @@ -19,6 +19,8 @@ #include "ThreadManager.h" +#include <sigc++/bind.h> + namespace Mad { namespace Common { @@ -53,6 +55,31 @@ void ThreadManager::workerFunc() { nextWork(); } + + // And let the new worker thread join us... + pushWork(sigc::bind(sigc::mem_fun(this, &ThreadManager::threadFinished), (gl_thread_t)gl_thread_self())); +} + +void ThreadManager::detach() { + if(!isThisMainThread()) { + Logger::log(Logger::CRITICAL, "Tried to detach main thread! This is just WRONG!"); + return; + } + + gl_lock_lock(runLock); + bool isRunning = running; + gl_lock_unlock(runLock); + if(!isRunning) // There's no point in creating a new worker thread when we aren't running anymore + return; + + gl_lock_lock(threadLock); + + if(workerThread == (gl_thread_t)gl_thread_self()) {// Already detached? + threads.insert(workerThread); + workerThread = gl_thread_create(&ThreadManager::workerStart, 0); + } + + gl_lock_unlock(threadLock); } void ThreadManager::pushWork(const sigc::slot<void> &newWork) { @@ -66,18 +93,20 @@ void ThreadManager::pushWork(const sigc::slot<void> &newWork) { void ThreadManager::doInit() { + gl_lock_init(threadLock); gl_lock_init(runLock); gl_lock_init(workLock); gl_cond_init(workCond); - gl_lock_lock(runLock); running = true; + gl_lock_lock(threadLock); + mainThread = (gl_thread_t)gl_thread_self(); workerThread = gl_thread_create(&ThreadManager::workerStart, 0); loggerThread = gl_thread_create(&ThreadManager::loggerStart, 0); - gl_lock_unlock(runLock); + gl_lock_unlock(threadLock); } void ThreadManager::doDeinit() { @@ -95,14 +124,29 @@ void ThreadManager::doDeinit() { gl_lock_unlock(workLock); gl_lock_unlock(runLock); - LogManager::get()->stopLoggerThread(); - + // We don't have to lock threadLock as detach() won't change workerThread when running is false gl_thread_join(workerThread, 0); + + // Now wait for all detached threads + gl_lock_lock(threadLock); + while(!threads.empty()) { + gl_thread_t thread = *threads.begin(); + gl_lock_unlock(threadLock); + + gl_thread_join(thread, 0); + + gl_lock_lock(threadLock); + threads.erase(thread); + } + gl_lock_unlock(threadLock); + + LogManager::get()->stopLoggerThread(); gl_thread_join(loggerThread, 0); gl_cond_destroy(workCond); gl_lock_destroy(workLock); gl_lock_destroy(runLock); + gl_lock_destroy(threadLock); } } diff --git a/src/Common/ThreadManager.h b/src/Common/ThreadManager.h index 07ab196..6e8616f 100644 --- a/src/Common/ThreadManager.h +++ b/src/Common/ThreadManager.h @@ -41,6 +41,8 @@ class ThreadManager : public Initializable { gl_thread_t mainThread, workerThread, loggerThread; std::set<gl_thread_t> threads; + gl_lock_t threadLock; + gl_lock_t runLock; bool running; @@ -64,19 +66,32 @@ class ThreadManager : public Initializable { void workerFunc(); + void threadFinished(gl_thread_t thread) { + gl_lock_lock(threadLock); + threads.erase(thread); + gl_lock_unlock(threadLock); + + gl_thread_join(thread, 0); + } + protected: virtual void doInit(); virtual void doDeinit(); public: - bool isThisMainThread() const { + bool isThisMainThread() { return (mainThread == (gl_thread_t)gl_thread_self()); } - bool isThisWorkerThread() const { - return (workerThread == (gl_thread_t)gl_thread_self()); + bool isThisWorkerThread() { + gl_lock_lock(threadLock); + bool ret = (workerThread == (gl_thread_t)gl_thread_self()); + gl_lock_unlock(threadLock); + return ret; } + void detach(); + void pushWork(const sigc::slot<void> &newWork); static ThreadManager* get() { |