Ergebnisse aus QThread lesen
Ergebnisse aus QThread lesen
Hi!
Ich versuche mich gerade daran QThread in Einsatz zu nehmen, habe mir dazu die Doku durchgeschaut, aber habe noch einige erständnisprobleme.
Meine Situation ist die folgende: Ich habe derzeit ein Hauptprogram(Mainthread) mit einer Gui. Für dieses Program sollen gewisse Daten für verschiedene Datensets berechnet werden(gleiche berechnungen für verschiedene Datensets). Das Ergebnis der Berechnungen soll in einem 3 Dimensionalen Vector abgespeichert werden (also prinzipiell vector<vector<vector<unsigned int>>>). Jetzt möchte ich für jedes Datenset einen neuen Thread starten um die Berechnungen durchzuführen und dann die Ergebnisse im Mainthread weiterverwenden. Dazu habe ich den code für die Berechnungen in die run() Methode des Threads getan. Als Input übergebe ich den Datensetnamen im onstruktor (oder mit einer setDatasetName() methode.
Meine Frage ist nun aber die folgende: Wie komme ich am besten an die Ergebnisse der Berechnungen?(also meinen vector<vector<vector<unsigned int>>>). Returnen kann ich aus der run() Methode kann ich ja schlecht etwas und mir ist auch nicht ganz klar ob ich Referenzen an die run() methode übergeben kann. Ich kann zwar Input Parameter für run in die Deklaration und Definition schreiben, aber wenn ich thread->start() aufrufe kann ich diese dann nicht übergeben. Nun habe ich auch noch über das QThreadStorage gelesen, aber ich bin mir auch hier nicht ganz über die Verwendung im klaren. Das QThreadStorage ist ja in meiner speziellen Thread Klasse(für die Berechnungen) eine Globle Variable - also kann ich im Thread einfach hineinschreiben. Aber wie greife ich vom Mainthread aus auf das QThreadStorage des Berechnungsthread zu sobald meine run() Methode fertig ist und die Daten in das QThreadStorage geschrieben hat? Ich wäre also dankbar für einen Tip, was die eleganteste Methode wäre um an meine Daten heranzukommen, und vielleicht noch einen kurzen Beispiel code zur Erklärung.
Vielen Dank & lg scr
Ich versuche mich gerade daran QThread in Einsatz zu nehmen, habe mir dazu die Doku durchgeschaut, aber habe noch einige erständnisprobleme.
Meine Situation ist die folgende: Ich habe derzeit ein Hauptprogram(Mainthread) mit einer Gui. Für dieses Program sollen gewisse Daten für verschiedene Datensets berechnet werden(gleiche berechnungen für verschiedene Datensets). Das Ergebnis der Berechnungen soll in einem 3 Dimensionalen Vector abgespeichert werden (also prinzipiell vector<vector<vector<unsigned int>>>). Jetzt möchte ich für jedes Datenset einen neuen Thread starten um die Berechnungen durchzuführen und dann die Ergebnisse im Mainthread weiterverwenden. Dazu habe ich den code für die Berechnungen in die run() Methode des Threads getan. Als Input übergebe ich den Datensetnamen im onstruktor (oder mit einer setDatasetName() methode.
Meine Frage ist nun aber die folgende: Wie komme ich am besten an die Ergebnisse der Berechnungen?(also meinen vector<vector<vector<unsigned int>>>). Returnen kann ich aus der run() Methode kann ich ja schlecht etwas und mir ist auch nicht ganz klar ob ich Referenzen an die run() methode übergeben kann. Ich kann zwar Input Parameter für run in die Deklaration und Definition schreiben, aber wenn ich thread->start() aufrufe kann ich diese dann nicht übergeben. Nun habe ich auch noch über das QThreadStorage gelesen, aber ich bin mir auch hier nicht ganz über die Verwendung im klaren. Das QThreadStorage ist ja in meiner speziellen Thread Klasse(für die Berechnungen) eine Globle Variable - also kann ich im Thread einfach hineinschreiben. Aber wie greife ich vom Mainthread aus auf das QThreadStorage des Berechnungsthread zu sobald meine run() Methode fertig ist und die Daten in das QThreadStorage geschrieben hat? Ich wäre also dankbar für einen Tip, was die eleganteste Methode wäre um an meine Daten heranzukommen, und vielleicht noch einen kurzen Beispiel code zur Erklärung.
Vielen Dank & lg scr
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Danke für die Antwort, aber ich muss nochmal blöd nachfragen:
Meinst du, dass ich einfach eine Member Variable vom typ vector<vector<vector<unsigned int>>> erstelle und diese mittels der getMethode returne? Oder soll bzw kann ich dass auch mit dem QThreadStorage machen. Ist das QThreadStorage für soetwas überhaupt nötig bzw. sinnvoll?
Und wäre dieser Ablauf in etwa ok?: Wenn mein Mainthread warten soll, bis die Berechnungsthreads fertig sind mache ich dies einfach mit this->wait(), nachdem ich thread1->start(), thread2->start() etc aufgerufen habe und und dann kopiere ich die Ergebnisse und lösche die threads dann wieder?!
Also ca so in code:
Danke nochmals & lg
Meinst du, dass ich einfach eine Member Variable vom typ vector<vector<vector<unsigned int>>> erstelle und diese mittels der getMethode returne? Oder soll bzw kann ich dass auch mit dem QThreadStorage machen. Ist das QThreadStorage für soetwas überhaupt nötig bzw. sinnvoll?
Und wäre dieser Ablauf in etwa ok?: Wenn mein Mainthread warten soll, bis die Berechnungsthreads fertig sind mache ich dies einfach mit this->wait(), nachdem ich thread1->start(), thread2->start() etc aufgerufen habe und und dann kopiere ich die Ergebnisse und lösche die threads dann wieder?!
Also ca so in code:
Code: Alles auswählen
...
thread1->start();
thread2->start();
...
this->wait(); //can I make the Mainthread wait for the other threads like this?
if(thread1->isFinished()){
myResutVec[i] = thread1->getResult();
delete thread1;
}
if(thread2->isFinished()){
myResutVec[i+1] = thread2->getResult();
delete thread2;
}
...
Um auf die Threads zu warten würde ich die Threads per Signal/Slot mit dem MainThread verdrahten. Wenn ein Thread fertig ist, wird einfach ein Signal emitiert, dass Du mit einem Slot deines Mainthreads (bzw. eines Objektes darin) verbindest.
Beachte, dass Du dafür in Deinen Threads einen Eventloop brauchst. Im Code würde es dann etwa so aussehen:
Thread.h:
Thread.cpp:
MainThread:
Jedenfall so in der Art....
Beachte, dass Du dafür in Deinen Threads einen Eventloop brauchst. Im Code würde es dann etwa so aussehen:
Thread.h:
Code: Alles auswählen
class MyThread : QThread {
...
public slots:
void startCalc();
signals:
void calcDone(MyThread*);
...
};
Code: Alles auswählen
...
void MyThread::run() {
exec();
}
void MyThread::startCalc() {
...
//Berechnung
...
emit calcDone(this);
}
Code: Alles auswählen
connect(this, SIGNAL(startCalculation()), thread1, SLOT(startCalc()));
connect(this, SIGNAL(startCalculation()), thread2, SLOT(startCalc()));
connect(this, SIGNAL(startCalculation()), thread3, SLOT(startCalc()));
connect(thread1, SIGNAL(calcDone(MyThread*)), this, SLOT(notify(MyThread*)));
connect(thread2, SIGNAL(calcDone(MyThread*)), this, SLOT(notify(MyThread*)));
connect(thread3, SIGNAL(calcDone(MyThread*)), this, SLOT(notify(MyThread*)));
...
myResutVec.clear();
thread1->start();
thread2->start();
thread3->start();
emit startCalculation();
}
void MainClass::notify(MyThread* thread) {
myResutVec.append(thread->getResults());
thread->quit();
while(thread->waitForFinished()); //sicherstellen, dass der Thread zu ende läuft, vor dem delete
delete thread;
if ( myResutVec.length == 3) {
//Ergebnisse weiterverarbeiten...
}
}
Nein, so besser nicht!brax hat geschrieben:...
1) QThread emittiert selber schon finished(), wenn die run() durch ist.
2) emit calcDone(this) ist irgendwie unnötig, oder? also, das this mitgeben. Da nimmt man das finished() und haut die Threads über den QSignalMapper auf einen SLOT. Oder pro Thread einen eigenen SLOT für das finished(), wenn die threads unterschiedliche Sachen machen, die getter also andere returns haben.
Danke für die Tips! Ich habs jetzt wie im folgenden gelöst. Ist zwar ziehmlich einfach aber es scheint zumindest zu funktionieren.
Hoffe zumindest dass ich da keinen groben Fehler drin hab der mir später auf den Kopf fällt.
lg
Hoffe zumindest dass ich da keinen groben Fehler drin hab der mir später auf den Kopf fällt.
Code: Alles auswählen
void MainWindow::startPrecalculations()
{
for(int i = 0; i < datasetList_.size(); i++)
{
inputImageFilename_ = datasetList_.at(i).toStdString();
PrecalculationThread* pcThread =
new PrecalculationThread(inputData);
connect(pcThread, SIGNAL(finished()), this, SLOT(usePrecalculations()));
calcThreadVec_.push_back(pcThread);
pcThread->start();
}
}
void MainWindow::usePrecalculations()
{
++numThreadsFinished_;
if(numThreadsFinished_ == calcThreadVec_.size())
{
OutputTypeVec* opStorage;
for(int i = 0; i < calcThreadVec_.size(); i++)
{
opStorage[i]= calcThreadVec_[i]->getOutput();
}
numThreadsFinished_ = 0;
//delete threads, and earease vector
while(!calcThreadVec_.empty()){
delete calcThreadVec_[0];
calcThreadVec_.erase(calcThreadVec_.begin());
}
proceedMainProgram(opStorage);
}
else
{
cout << "Waiting for other Threads to finish" << endl;
}
}
Da die Erzeugung eines Threads eine relativ teure Operation ist, frage ich mich bei der ganzen Sache, wie oft diese Berechnungen ausgeführt werden. Wenn das häufiger passiert, würde ich darauf verzichten, die Dinger jedesmal neu zu erzeugen bzw. nach der Berechnung gleich zu beenden und zu löschen. Darum hätte ich ihnen auch ihren eigenen Eventloop gegeben, und die Berechnung dann je nach bedarf per Signal gestartet. Dann kann man natürlich nicht das finished() Signal nehmen...1) QThread emittiert selber schon finished(), wenn die run() durch ist.
Angenommen man behält die Threads (quasi als Threadpool) dann hilft der Parameter die Ergebnisse einer Berechnung zuzuordnen. Man braucht sie sich nicht (wie in der jetzigen Lösung) als Member zu speichern und man braucht nicht notwendiger weise auf alle Threads zu warten....2) emit calcDone(this) ist irgendwie unnötig, oder? also, das this mitgeben. Da nimmt man das finished() und haut die Threads über den QSignalMapper auf einen SLOT.
Wenn es natürlich tatsächlich so ist, dass die Berechnung nur einmal durchgeführt wird und die Anwendung eh auf das Ende der Berechnung wartet, ist es sowieso fragwürdig, ob ein Thread überhaupt notwendig ist, oder ob man eher Qts eingebauten Threadpool (QConcurrent) benutzen sollte....
@brax: Geb ich dir Recht.
Wenn halt die Threads (wie in deiner Lösung anzunehmen war) schon als Member gespeichert sind, ist das zusätzliche SIGNAL unnötig.
Es wäre jetzt interessant, wie groß die zu berechnende Datenmenge ist, ob alles wirklich parallel gemacht werden muss, oder ob man EINEN Workerthread nimmt, und nach dem finished() mit neuen Daten füttern kann.
Bei Threads muss man auch aufpassen, wegen Synchronisierung der Threads. Ich würde die Threads nach der Erzeugung nicht sofort starten, da es gut möglich ist, dass der erste Thread fertig ist bevor der zweite fertig erzeugt wurde. Dann bekommst du gaaanz lustige Resultate
Da wird dann angenommen dass alle Threads durch sind, und schon mit Auswerten angefangen.
Wenn halt die Threads (wie in deiner Lösung anzunehmen war) schon als Member gespeichert sind, ist das zusätzliche SIGNAL unnötig.
Es wäre jetzt interessant, wie groß die zu berechnende Datenmenge ist, ob alles wirklich parallel gemacht werden muss, oder ob man EINEN Workerthread nimmt, und nach dem finished() mit neuen Daten füttern kann.
Bei Threads muss man auch aufpassen, wegen Synchronisierung der Threads. Ich würde die Threads nach der Erzeugung nicht sofort starten, da es gut möglich ist, dass der erste Thread fertig ist bevor der zweite fertig erzeugt wurde. Dann bekommst du gaaanz lustige Resultate