utilities/src/workerthread.cpp

00001 /********************************************************************************
00002  *  FARSA Experiments Library                                                   *
00003  *  Copyright (C) 2007-2012                                                     *
00004  *  Gianluca Massera <emmegian@yahoo.it>                                        *
00005  *  Stefano Nolfi <stefano.nolfi@istc.cnr.it>                                   *
00006  *  Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it>                         *
00007  *                                                                              *
00008  *  This program is free software; you can redistribute it and/or modify        *
00009  *  it under the terms of the GNU General Public License as published by        *
00010  *  the Free Software Foundation; either version 2 of the License, or           *
00011  *  (at your option) any later version.                                         *
00012  *                                                                              *
00013  *  This program is distributed in the hope that it will be useful,             *
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00016  *  GNU General Public License for more details.                                *
00017  *                                                                              *
00018  *  You should have received a copy of the GNU General Public License           *
00019  *  along with this program; if not, write to the Free Software                 *
00020  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00021  ********************************************************************************/
00022 
00023 #include "workerthread.h"
00024 
00025 namespace farsa {
00026 
00027 WorkerThread::WorkerThread( QObject* parent ) :
00028     QThread(parent),
00029     operations(),
00030     mutex(),
00031     waitForOperationsToDo(),
00032     operation(NULL),
00033     quitRequested(false),
00034     exceptions() {
00035 }
00036 
00037 WorkerThread::~WorkerThread() {
00038     foreach (BaseException *e, exceptions) {
00039         delete e;
00040     }
00041 }
00042 
00043 void WorkerThread::addOperation( ThreadOperation* newOperation ) {
00044     mutex.lock();
00045     operations.enqueue( newOperation );
00046     mutex.unlock();
00047     if ( operations.size() == 1 ) {
00048         // wake the run thread because now there is something to do
00049         waitForOperationsToDo.wakeAll();
00050     }
00051 }
00052 
00053 void WorkerThread::stopCurrentOperation() {
00054     mutex.lock();
00055     if ( operation ) {
00056         operation->stop();
00057     }
00058     mutex.unlock();
00059 }
00060 
00061 void WorkerThread::run() {
00062     forever {
00063         mutex.lock();
00064         // We have to check quitRequested here (not only after waitForOperationsToDo.wait()) because quit() can
00065         // be called before run() starts. In that case quitRequested is already true, but we lost the "signal"
00066         // that should wake us when on the wait condition and so we would sleep indefinitely
00067         if ( quitRequested ) {
00068             mutex.unlock();
00069             return;
00070         }
00071         if ( operations.size() == 0 ) {
00072             // wait the adding of an operation
00073             waitForOperationsToDo.wait( &mutex );
00074         }
00075         if ( quitRequested ) {
00076             mutex.unlock();
00077             return;
00078         }
00079         operation = operations.dequeue();
00080         mutex.unlock();
00081         try {
00082             operation->run();
00083         } catch (BaseException& e) {
00084             BaseException* cloned = e.clone();
00085             exceptions.append(cloned);
00086 
00087             emit exceptionDuringOperation(cloned);
00088         } catch (...) {
00089             UnknownException* e = new UnknownException();
00090             exceptions.append(e);
00091 
00092             emit exceptionDuringOperation(e);
00093         }
00094         mutex.lock();
00095         delete operation;
00096         operation = NULL;
00097         mutex.unlock();
00098         if ( quitRequested ) {
00099             return;
00100         }
00101     }
00102 }
00103 
00104 void WorkerThread::quit() {
00105     mutex.lock();
00106     quitRequested = true;
00107     mutex.unlock();
00108     stopCurrentOperation();
00109     waitForOperationsToDo.wakeAll();
00110     wait();
00111 }
00112 
00113 } // end namespace farsa