/* * 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 "FdManager.h" #include #include #include namespace Mad { namespace Net { ThreadManager ThreadManager::threadManager; void ThreadManager::workerFunc() { while(true) { boost::unique_lock lock(runLock); if(!running || !isThisWorkerThread()) break; lock.unlock(); boost::unique_lock lock2(workLock); while(work.empty()) { workCond.wait(lock2); if(!running) return; } boost::function0 nextWork = work.front(); work.pop(); lock2.unlock(); nextWork(); } // And let the new worker thread join us... // TODO pushWork(sigc::bind(sigc::mem_fun(this, &ThreadManager::threadFinished), (gl_thread_t)gl_thread_self())); } void ThreadManager::detach() { if(!isThisMainThread()) { Common::Logger::log(Common::Logger::CRITICAL, "Tried to detach main thread! This is just WRONG!"); return; } runLock.lock(); bool isRunning = running; runLock.unlock(); if(!isRunning) // There's no point in creating a new worker thread when we aren't running anymore return; threadLock.lock(); if(workerThread->get_id() == boost::this_thread::get_id()) {// Already detached? threads.add_thread(workerThread); workerThread = new boost::thread(std::mem_fun(&ThreadManager::workerFunc), this); } threadLock.unlock(); } void ThreadManager::pushWork(const boost::function0 &newWork) { workLock.lock(); work.push(newWork); workLock.unlock(); workCond.notify_one(); } void ThreadManager::doInit() { running = true; threadLock.lock(); mainThreadId = boost::this_thread::get_id(); workerThread = new boost::thread(std::mem_fun(&ThreadManager::workerFunc), this); loggerThread = new boost::thread(std::mem_fun(&Common::LogManager::loggerThread), Common::LogManager::get()); ioThread = new boost::thread(std::mem_fun(&FdManager::ioThread), FdManager::get()); threadLock.unlock(); } void ThreadManager::doDeinit() { if(!isThisMainThread()) { // TODO Critical error!!! return; } // First set running = false so the worker threads quit boost::lock(runLock, workLock); running = false; workLock.unlock(); runLock.unlock(); workCond.notify_one(); // We don't have to lock threadLock as detach() won't change workerThread when running is false workerThread->join(); delete workerThread; // Now wait for all detached threads threads.join_all(); // IO thread is next FdManager::get()->stopIOThread(); ioThread->join(); delete ioThread; // Finally, the logger thread has to die Common::LogManager::get()->stopLoggerThread(); loggerThread->join(); delete loggerThread; } } }