From 766c56a693e8b1bd4293459bb256abdc0515a0b5 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 9 Jun 2009 19:01:02 +0200 Subject: Teile der Namespaces Common und Net in den neuen Namespace Core verschoben --- src/Core/ThreadManager.cpp | 143 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 src/Core/ThreadManager.cpp (limited to 'src/Core/ThreadManager.cpp') diff --git a/src/Core/ThreadManager.cpp b/src/Core/ThreadManager.cpp new file mode 100644 index 0000000..abc0bc6 --- /dev/null +++ b/src/Core/ThreadManager.cpp @@ -0,0 +1,143 @@ +/* + * 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 "Logger.h" +#include "LogManager.h" + +#include + +namespace Mad { +namespace Core { + +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()) { + Logger::log(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(ioService)); + + mainThreadId = boost::this_thread::get_id(); + workerThread.reset(new boost::thread(&ThreadManager::workerFunc, this)); + loggerThread.reset(new boost::thread(&LogManager::loggerThread, LogManager::get())); + ioThread.reset(new boost::thread((std::size_t(boost::asio::io_service::*)())&boost::asio::io_service::run, &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(); + ioService.stop(); + ioThread->join(); + + // Finally, the logger thread has to die + LogManager::get()->stopLoggerThread(); + loggerThread->join(); +} + +} +} -- cgit v1.2.3