Seite 1 von 1

Brechnung in mehreren Threads

Verfasst: 26. Januar 2011 08:48
von karls0n
Hallo,

ich habe hier nun eine Weile gesucht aber nichts gefunden was mir so richtig helfen könnte.

Ich habe ein Programm (ohne GUI) welches Berechnungen durchführt. Um diese zu beschleunigen würde ich diese gern parallelisieren durch Threads.

Ich habe eine Main Klasse und jeweils eine Klasse für jede Berechnung, die Funktionen. Die Funktionen erhalten beim Aufruf die jeweils aktuelle Liste. Dabei werden viele Listen erzeugt und die Berechnungen für alle ausgeführt.

Wie realisiere ich das am besten?

Kennt jemand ein Beispiel?

Ich habe gelesen, dass man Objekte in einen Thread stecken kann, wie könnten dann Berechnungen ausgeführt werden? (moveToThread() )

Gruß,
Karls0n

Ich habe mal einen Teil der Klassen zusammengefügt und angehangen.

Verfasst: 26. Januar 2011 09:01
von RavenIV
Nur so als Hinweis:
Die Berechnungen werden nicht unbedingt schneller, nur weil sie in mehreren Threads quasi parallel bearbeitet werden.
Je nach Aufgabe der Threads wird alles sogar langsamer.

Threads sind kein Allheilmittel.

Verfasst: 26. Januar 2011 10:39
von karls0n
RavenIV hat geschrieben:Nur so als Hinweis:
Die Berechnungen werden nicht unbedingt schneller, nur weil sie in mehreren Threads quasi parallel bearbeitet werden.
Je nach Aufgabe der Threads wird alles sogar langsamer.

Threads sind kein Allheilmittel.
Hallo,

ja da hast du natürlich recht, ich habe es mit QThreads mal getestet.
Erst ab einer gewissen Listenlänge war das Threading schneller. Jedoch war meine Lösung nicht die Beste und ich würde diese gern optimieren und vielleicht mit den Objekten arbeiten.

Verfasst: 27. Januar 2011 17:58
von karls0n
Hallo,

ich habe mich ein wenig mit dem moveToThread() beschäftigt, jedoch schlägt dies fehl.
Ich habe mich an eine Anleitung gehalten jedoch funktioniert diese und meine Konstruktion nicht.
Könnte mir jemand sagen wo der Fehler liegt?


main.cpp

Code: Alles auswählen

#include "avg.h"
#include "euclid.h"

#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui/QApplication>

QList<int> tInteger;
QList<int> qInteger;
QList<int> zInteger;

void initialize()
{
  for (int i = 0; i < 20; i++) {
    tInteger.append(i);
    qInteger.append(i % 10);
  }
}

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  initialize();

  //Thread
  qDebug() << "Thread:";
  avg a(tInteger, qInteger);
  a.start();
  a.wait();
  printf("average: %f\n", a.getAvgDistance());


  QThread eThread;
  //Object in Thread
  euclid e(tInteger, qInteger);
  e.moveToThread(&eThread);
  e.connect(&eThread, SIGNAL(started()), SLOT(euclidCalculation()));
  e.connect(&eThread, SIGNAL(euclidFinished()), SLOT(quit()));
  app.connect(&eThread, SIGNAL(euclidFinished()), SLOT(quit()));
  eThread.start();

  printf("average: %f\n", e.getEuclidDistance());
  return app.exec();
}
euclid.cpp

Code: Alles auswählen

#include "euclid.h"

euclid::euclid(QList<int> const &A, QList<int> const &B)
{
  euclidListA = A;
  euclidListB = B;
}

euclid::~euclid()
{
}

double euclid::getEuclidDistance()
{
  return euclidDistance;
}

void euclid::euclidCalculation()
{
  double distance = 0;
  printf("euclidCalculate\n");
  for (int i = 0; i < euclidListA.size(); i++) {
    distance += pow(euclidListA.at(i) - euclidListB.at(i), 2);
  }
  euclidDistance = sqrt(distance);
  emit euclidFinished();
};
euclid.h

Code: Alles auswählen

#ifndef EUCLID_H
#define	EUCLID_H

#include <QtCore/QList>
#include <QtCore/QObject>
#include <math.h>

class euclid : public QObject {
  Q_OBJECT

public:
  double euclidDistance;
  QList<int> euclidListA;
  QList<int> euclidListB;

  euclid(QList<int> const &A, QList<int> const &B);

  virtual ~euclid();
  double getEuclidDistance();

public slots:
  void euclidCalculation();
signals:
  void euclidFinished();
private:

};
#endif	/* EUCLID_H */
Die Ausführung des Thread funktioniert ohne probleme, nur beim Objekt in Verbindung mit moveToThread kommt zu einer Endlosschleife. Sind die Signale falsch gesetzt?

Grüße,
Karls0n

Verfasst: 27. Januar 2011 22:36
von franzf
Eine kleine Übung:
Schau dir connect in der Doku nochmal GENAU an. Überleg dir, welche Version du verwendest. Dann überlegst du, ob die angegebenen Sender-Objekte auch die SIGNALS haben, die du willst, ebenso ob die Empfänger-Objekte entsprechende SLOTS haben.
Solche falschen Connections werden dir auf der Console als Warnung ausgegeben.

Verfasst: 27. Januar 2011 23:12
von karls0n
Hallo,
danke für die Hinweise!
Sie halfen mir die ersten Probleme zu lösen.
Ich hatte die falsche Art Application, welche somit nichts mit den Signalen anfangen konnte und mein Signalgeber war falsch.Leider wurden mir keine Warnungen angezeigt, das hätte es wohl einfacher gestaltet.

Mein Problem ist noch, dass zu spät berechnet wird. In der letzten printf Anweisung wird mir der Inhalt der Variable bzw. ihre Adresse angezeigt. Das Ergebnis wird also vor der Berechnung zurück gegeben. Erst nach bzw. kurz vor dem "return app.exec()" scheint die Berechnung statt zu finden.
Hast Du dazu vielleicht auch einen Hinweis oder eine Erklärung?

Code: Alles auswählen

#include "avg.h"
#include "euclid.h"

#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui/QApplication>

QList<int> tInteger;
QList<int> qInteger;
QList<int> zInteger;

void initialize()
{
  for (int i = 0; i < 3; i++) {
    tInteger.append(i);
    qInteger.append(i % 10);
    zInteger.append(i % 20);
  }
}

int main(int argc, char *argv[])
{
  initialize();
  QCoreApplication app(argc, argv);
  
  //Thread
  avg a(tInteger, qInteger);
  a.start();
  a.wait();
  printf("average: %f\n", a.getAvgDistance());
  
  //Object in Thread
  QThread eThread;
  euclid e(tInteger, qInteger);
  
  e.moveToThread(&eThread);
  e.connect(&eThread,SIGNAL(started()),SLOT(euclidCalculation()));
  
  eThread.connect(&e,SIGNAL(euclidFinished()),SLOT(quit()));
  app.connect(&e,SIGNAL(euclidFinished()),SLOT(quit()));

  eThread.start();
  printf("EuclidDistance: %f\n", e.getEuclidDistance());
  return app.exec();
}
Grüße,
Karls0n

Verfasst: 27. Januar 2011 23:19
von franzf
karls0n hat geschrieben:Hast Du dazu vielleicht auch einen Hinweis oder eine Erklärung?
Sicher. Lies dir in der Doku durch, was app.exec() macht. :P
Es startet die EventLoop. Signal/Slot wird darüber auch gehandelt. Damit werden die SLOTS erst im exec() verarbeitet.

Verfasst: 30. Januar 2011 15:30
von karls0n
Hallo,

danke franzf für die Hilfe und Geduld.

Das Programm läuft nun eigentlich ohne Probleme. Ich habe mehrere Berechnungen (5) in einen Prozess gepackt und lasse diese alle "gleichzeitig" laufen und beende die QCoreApplication mit einer gesonderten Methode. Diese kontrolliert ob alle gestarteten Threads auch beendet sind und sendet dann an ein "quit()" an die QCoreApp. Ein einmaliger Durchlauf funktioniert ohne Probleme.

Ich habe mehrere Testreihen die generiert werden und dann ausgewertet werden sollen. Jedoch "stirbt" das Program nach dem mehrfachen Aufruf (meist zwischen dem 4-9).
Ich habe mir mit "QCoreApplication::applicationPid()" die Prozess ID ausgeben lassen diese ist stets gleich. Ich habe im Taskmanager gesehen das beim Absturz das Program meist 5-10 Threads hat, daher mein Verdacht, das die QCoreApplication bzw. deren Prozesse nicht richtig beendet werden.

Kann es daran liegen das ein mehrfaches Ausführen fehl schlägt? Die QCoreApplication sollte beendet sein, deshalb kann ich mir nicht erklären wo der Fehler liegt.
Ich erhalte leider auch keine Fehlermeldung.


Karls0n