workthread.cpp

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** @file workthread.cpp Implementation of WorkThread API */
00020 
00021 #include <hn/hnprec.h>
00022 #include <hn/workthread.h>
00023 
00024 #ifdef _MSC_VER
00025         // 'this' used in base member initializer list
00026         #pragma warning(disable:4355)
00027 #endif
00028 
00029 // ThreadWork class
00030 // ----------------
00031 ThreadWork::ThreadWork() : m_valid(true), m_complete(false) {}
00032 ThreadWork::~ThreadWork() {}
00033 void ThreadWork::cancel() {
00034         boost::mutex::scoped_lock l(m_validLock);
00035         m_valid = false;
00036 }
00037 bool ThreadWork::isValid() {
00038         boost::mutex::scoped_lock l(m_validLock);
00039         return m_valid;
00040 }
00041 bool ThreadWork::isComplete() {
00042         boost::mutex::scoped_lock l(m_completeLock);
00043         return m_complete;
00044 }
00045 void ThreadWork::setComplete() {
00046         boost::mutex::scoped_lock l(m_completeLock);
00047         m_complete = true;
00048 }
00049 
00050 // WorkThread class
00051 // ----------------
00052 WorkThread::WorkThread() :
00053         m_exiting(false), m_worker(boost::bind(&WorkThread::threadLoop, this))
00054 {}
00055 WorkThread::~WorkThread() {
00056         exit();
00057         m_worker.join();
00058 }
00059 WorkThread& WorkThread::instance() {
00060         static WorkThread wt;
00061         return wt;
00062 }
00063 
00064 bool WorkThread::checkExit() {
00065         boost::mutex::scoped_lock l(m_exitLock);
00066         return m_exiting;
00067 }
00068 void WorkThread::exit() {
00069         boost::mutex::scoped_lock l1(m_notifyLock);
00070         boost::mutex::scoped_lock l2(m_exitLock);
00071         m_exiting = true;
00072         m_notify.notify_all();
00073 }
00074 void WorkThread::postWork(ThreadWorkPtr work) {
00075         boost::mutex::scoped_lock l(m_notifyLock);
00076         boost::mutex::scoped_lock l1(m_queueLock);
00077         m_queue.push_back(work);
00078         m_notify.notify_all();
00079 }
00080 void WorkThread::threadLoop() {
00081         ThreadWorkPtr wrk;
00082         while (!checkExit()) {
00083                 if (!wrk) {
00084                         boost::mutex::scoped_lock l1(m_notifyLock);
00085                         {
00086                                 boost::mutex::scoped_lock l2(m_queueLock);
00087                                 if (m_queue.size()) {
00088                                         wrk = m_queue.front();
00089                                         m_queue.pop_front();
00090                                 }
00091                         }
00092                         if (!wrk) {
00093                                 m_notify.wait(l1);
00094                         }
00095                 }
00096                 if (wrk && wrk->isValid() && !wrk->isComplete()) try {
00097                         wrk->process();
00098                 } catch (std::exception &e) {
00099                         logError(boost::format(
00100                                 "Fatal exception at WorkThread: %s"
00101                         ) % e.what());
00102                         wrk.reset();
00103                 } catch (...) {
00104                         logError(boost::format(
00105                                 "Unknown fatal error at WorkThread."
00106                         ));
00107                         wrk.reset();
00108                 } else {
00109                         wrk.reset();
00110                 }
00111         }
00112 }