/* * 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 "Connection.h" #include #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... pushWork(boost::bind(&ThreadManager::threadFinished, this, boost::this_thread::get_id())); } void ThreadManager::detach() { if(isThisMainThread()) { Common::Logger::log(Common::Logger::CRITICAL, "Tried to detach main thread! This is just WRONG!"); return; } { boost::lock_guard lock(runLock); if(!running) return; // There's no point in creating a new worker thread when we aren't running anymore } threadLock.lock(); if(workerThread->get_id() == boost::this_thread::get_id()) {// Already detached? threads.insert(std::make_pair(boost::this_thread::get_id(), workerThread)); workerThread.reset(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(); ioWorker.reset(new boost::asio::io_service::work(Connection::ioService)); mainThreadId = boost::this_thread::get_id(); workerThread.reset(new boost::thread(&ThreadManager::workerFunc, this)); loggerThread.reset(new boost::thread(&Common::LogManager::loggerThread, Common::LogManager::get())); ioThread.reset(new boost::thread((std::size_t(boost::asio::io_service::*)())&boost::asio::io_service::run, &Connection::ioService)); 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(); // Now wait for all detached threads while(!threads.empty()) { threadFinished(threads.begin()->first); } // IO thread is next ioWorker.reset(); Connection::ioService.stop(); ioThread->join(); // Finally, the logger thread has to die Common::LogManager::get()->stopLoggerThread(); loggerThread->join(); } } }