Brechnung in mehreren Threads

Alles rund um die Programmierung mit Qt
Antworten
karls0n
Beiträge: 5
Registriert: 24. Januar 2011 18:55

Brechnung in mehreren Threads

Beitrag 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.
Dateianhänge
min.zip
Ein Auszug als Zip.
(1.56 KiB) 134-mal heruntergeladen
RavenIV
Beiträge: 267
Registriert: 21. Januar 2009 14:24
Wohnort: Waldshut

Beitrag 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.
Linux, das längste Text-Adventure aller Zeiten
karls0n
Beiträge: 5
Registriert: 24. Januar 2011 18:55

Beitrag 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.
karls0n
Beiträge: 5
Registriert: 24. Januar 2011 18:55

Beitrag 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
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag 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.
karls0n
Beiträge: 5
Registriert: 24. Januar 2011 18:55

Beitrag 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
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag 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.
karls0n
Beiträge: 5
Registriert: 24. Januar 2011 18:55

Beitrag 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
Antworten