PARP Research Group University of Murcia, Spain


src/qvcore/qvworker.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008, 2009. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024  
00025 #include <iostream>
00026 
00027 #include <QDebug>
00028 #include <QMutex>
00029 #include <QWaitCondition>
00030 #include <QApplication>
00031 
00032 #include <QVWorker>
00033 #include <QVCameraWorker>
00034 
00035 QVWorker::QVWorker(const QString name):QVPropertyContainer(name), numIterations(0), status(Running), triggerList(), minms(0)
00036         {
00037         qDebug() << "QVWorker::QVWorker(" << name << ")";
00038         Q_ASSERT_X(qvApp != NULL, "QVWorker::QVWorker()", "QVApplication doesn't exists");
00039         if (qvApp == NULL)
00040                 {
00041                 QString str = "QVWorker::QVWorker(): the QVWorker cannot be created before the QVApplication instance. Aborting now.";
00042                 std::cerr << qPrintable(str) << std::endl;
00043                 exit(1);
00044                 }
00045 
00046         addProperty<int>("max worker iterations", inputFlag | guiInvisible | internalProp, -1, "Stablishes maximal number of iterations to execute worker");
00047         maxIterations = getPropertyValue<int>("max worker iterations");
00048 
00049         addProperty<bool>("stats enabled", inputFlag | guiInvisible | internalProp, TRUE, "Stablishes if the worker's cpu stats will be enabled");
00050         statsEnabled = getPropertyValue<bool>("stats enabled");
00051         if (statsEnabled) cpuStatControler = new QVStatControler();
00052         if (statsEnabled)       addProperty<QVStat>("cpu stats", outputFlag, cpuStatControler->value(), "CPU stats's Statistics");
00053         else                            addProperty<QVStat>("cpu stats", outputFlag, QVStat(), "CPU stats's Statistics");
00054 
00055         informer.setParent(this); // set the informer's parent = this, in order to it will be moved to the worker's thread when the qvApp do worker->moveToThread(worker)
00056 
00057         addProperty<int>("print stats frequency", inputFlag | guiInvisible | internalProp, 0, "Number of iterations to print CPU usage statistics.");
00058         const int printStatsFrequency = getPropertyValue<int>("print stats frequency");
00059 
00060         if (printStatsFrequency > 0)
00061                 setPrintStatsFrequency(printStatsFrequency);
00062 
00063         qDebug() << "QVWorker::QVWorker(" << name << ") <- return";
00064         };
00065 
00066 QVWorker::QVWorker(const QVWorker &other):QThread(), QVPropertyContainer(other), statsEnabled(other.statsEnabled), numIterations(other.numIterations),
00067         maxIterations(other.maxIterations), status(other.status), triggerList(other.triggerList), iterationTime(other.iterationTime), curms(other.curms),
00068         minms(other.minms)
00069         {
00070         if (statsEnabled) cpuStatControler = new QVStatControler();
00071         }
00072 
00073 QVWorker::~QVWorker()
00074         {
00075         if (statsEnabled)
00076                 delete cpuStatControler;
00077 
00078         informer.setParent(0); // in order not to delete the informer object, when all its childrens will be deleted
00079         }
00080 /*
00081 void QVWorker::unlink()
00082         {
00083         if(status == Finished)
00084                 QVPropertyContainer::unlink();
00085         else
00086                 std::cerr << "WARNING: A worker only can be unlinked if the worker's status is Finished." << std::endl;
00087         }
00088 */
00089 void QVWorker::run()
00090         {
00091         qDebug() << "QVWorker::run()";
00092 
00093         while(status != Finished)
00094                 {
00095                 qDebug() << "Processing events in worker " << qPrintable(getName());
00096 
00097                 // First, we check if there are any pending signals, and if so, we
00098                 // execute their associated slots:
00099                 qApp->processEvents();
00100 
00101                 qDebug() << "QVWorker::iterate(): iteration" << numIterations;
00102         
00103                 // Avoids "apparent hanging" (greedy ocupation of CPU by extremely fast
00104                 // workers, such as paused ones). It is just 1 millisecond, so
00105                 // it should not be appreciable in any practical situation.
00106                 usleep(1000);
00107 
00108                 switch (status)
00109                         {
00110                         case RunningOneStep:
00111                                 qDebug() << "QVWorker::iterate(): RunningOneStep";
00112                                 status = Paused;
00113 
00114                         case Running:
00115                                 iterationTime.start();
00116                                 foreach(QList<QVPropertyContainer *> level, slavesByLevel) // Iterate all its slaves (included itselve)
00117                                         foreach(QVPropertyContainer * slave, level)
00118                                                 if(dynamic_cast<QVWorker *>(slave) != NULL) ((QVWorker *)slave)->workerIterate();
00119 
00120                                 curms = iterationTime.elapsed();
00121                                 if(minms > curms)
00122                                         usleep(1000*(minms-curms));
00123                                 /*if(numIterations!=1) // First iteration time is too noisy:
00124                                         acumms = (acumms*(numIterations-2) + curms) / (numIterations-1);
00125                                 std::cout << "-----> curms=" << curms << " acumms=" << acumms << "\n";*/
00126                                 break;
00127 
00128                         case Stoped:
00129                                 // A stopped worker should never block anybody, but keeps linked to
00130                                 // other workers (otherwise, it would simply be deleted). So, it must
00131                                 // read its inputs an write its outputs always, even being stopped.
00132                                 readInputProperties();
00133                                 writeOutputProperties();
00134                                 usleep(100); // This avoids spurious CPU consuming when stopped.
00135                                 break;
00136 
00137         
00138                         case Paused:
00139                                 qDebug() << "QVWorker::iterate(): Paused";
00140                                 if(dynamic_cast<QVCameraWorker*>(this) != NULL)
00141                                         {
00142                                         // A special pause case for camera workers: we do not want paused cameras
00143                                         // to block linked workers:
00144                                         readInputProperties();
00145                                         writeOutputProperties();
00146                                         }
00147                                 usleep(100); // This avoids spurious CPU consuming when paused.
00148                                 break;
00149 
00150                         case Finished:
00151                                 qDebug() << "QVWorker::iterate(): Finished";
00152                                 break;
00153                         }
00154 
00155                 if (maxIterations != -1 && numIterations >= maxIterations)
00156                         finish();
00157 
00158                 qDebug() << "QVWorker::iterate() <- return";
00159                 }
00160 
00161 
00162         foreach(QList<QVPropertyContainer *> level, slavesByLevel) // Return to the main thread all its slaves (included itselve)
00163                 foreach(QVPropertyContainer * slave, level)
00164                         if(dynamic_cast<QVWorker *>(slave) != NULL) ((QVWorker *)slave)->moveToThread(qvApp->thread());
00165 
00166         foreach(QList<QVPropertyContainer *> level, slavesByLevel) // Unlink all its slaves (included itselve)
00167                 foreach(QVPropertyContainer * slave, level)
00168                         if(dynamic_cast<QVWorker *>(slave) != NULL) {
00169                                 QMutexLocker locker(&qvApp->mutex); // in safe mode with other thread's unlinks and with the canvas viewer()
00170                                 ((QVWorker *)slave)->unlink();
00171                         }
00172 
00173         qApp->processEvents();
00174 
00175         qDebug() << "QVWorker::run() <- return";
00176         }
00177 
00178 void QVWorker::workerIterate()
00179         {
00180         if (statsEnabled) cpuStatControler->step();
00181         emit startIteration(); // if it is connect to a camera, it will be wait the camera grab()
00182         readInputProperties();
00183         timeFlag("System");
00184         iterate();
00185         if (statsEnabled) setPropertyValue<QVStat>("cpu stats", cpuStatControler->value());
00186         writeOutputProperties();
00187         numIterations++;
00188         emit endIteration(getId(), getIteration());
00189         }
00190 



QVision framework. PARP research group, copyright 2007, 2008.