/* * 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 Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this program. If not, see . */ #include "ThreadManager.h" #include "Application.h" #include "LogManager.h" #include namespace Mad { namespace Core { 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() { { 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 or no worker thread? 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(); } ThreadManager::ThreadManager(Application *application0) : application(application0), running(true) { threadLock.lock(); ioWorker.reset(new boost::asio::io_service::work(application->getIOService())); mainThreadId = boost::this_thread::get_id(); workerThread.reset(new boost::thread(&ThreadManager::workerFunc, this)); loggerThread.reset(new boost::thread(&LogManager::loggerThread, application->getLogManager())); ioThread.reset(new boost::thread((std::size_t(boost::asio::io_service::*)())&boost::asio::io_service::run, &application->getIOService())); threadLock.unlock(); } ThreadManager::~ThreadManager() { 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(); ioThread->join(); // Finally, the logger thread has to die application->getLogManager()->stopLoggerThread(); loggerThread->join(); } } }