/* * ThreadManager.cpp * * Copyright (C) 2009 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "ThreadManager.h" #include namespace Mad { namespace Common { ThreadManager ThreadManager::threadManager; void ThreadManager::workerFunc() { while(true) { gl_lock_lock(runLock); if(!running || !isThisWorkerThread()) { gl_lock_unlock(runLock); return; } gl_lock_unlock(runLock); gl_lock_lock(workLock); while(work.empty()) { gl_cond_wait(workCond, workLock); if(!running) { gl_lock_unlock(workLock); return; } } sigc::slot nextWork = work.front(); work.pop(); gl_lock_unlock(workLock); 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 &newWork) { gl_lock_lock(workLock); work.push(newWork); gl_cond_signal(workCond); gl_lock_unlock(workLock); } void ThreadManager::doInit() { gl_lock_init(threadLock); gl_lock_init(runLock); gl_lock_init(workLock); gl_cond_init(workCond); 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(threadLock); } void ThreadManager::doDeinit() { if(!isThisMainThread()) { // TODO Critical error!!! return; } gl_lock_lock(runLock); gl_lock_lock(workLock); running = false; gl_cond_signal(workCond); gl_lock_unlock(workLock); gl_lock_unlock(runLock); // 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); } } }