Pro Worker-Thread eine GUI-Thread?
Pro Worker-Thread eine GUI-Thread?
Hi,
ich habe bei meiner Aufgabe mit Sensoren zu tun, die ich gelegentlich Abfrage oder irgendwelche Kommandos zu ihnen schicke.
Dabei soll das ganze halt Multithreading-Fähig gemacht werden.
Dafür will ich pro erfassten Sensor einen Thread erzeugen.
Die Daten die ich vom Sensor bekomme, die schickt mein Master-Thread/Prozess (der Koordinator) (bin hierbei noch nicht sicher obs ein thread sein soll) an den jeweiligen Worker-Thread.
Frage1:
Die Daten die im jeweiligen Worker-Thread landen müssen visualisiert werden. (z.B. pro Sensor ein TAB im Hauptdialog)
Ist es sinnvoll pro Worker-Thread eine Gui-Thread zu erzeugen oder reicht der einzige std. GUI-Thread?
Frage2:
Die Daten, die vom Worker-Thread angenommen und eventuell bearbeitet worden sind müssen nun visualisiert werden.
Meine Idee war es die zu visualisierenden Daten an die GUI via Signal/Slot zu verschicken und regelmäßig zu updaten (bei Wertveränderungen usw.).
Frage3:
Das ist bezogen auf Frage 1.
Wenn die von mir genannten Worker-Threads keine Rechenaufgaben bekommen, sondern nur Daten bekommen und diese visualisieren müssen. Oder die Daten, die der Benutzer über die GUI eingibt/verändert an die Sensoren zurückgeschickt werden müssen ( ohne etwas zu berechnen).
Sollte man hierbei auf Worker-Threads verzichten und direkt pro Sensor Gui-Threads erstellen?
Stehe gerade etwas auf dem Schlauch bez. Threading.
ich habe bei meiner Aufgabe mit Sensoren zu tun, die ich gelegentlich Abfrage oder irgendwelche Kommandos zu ihnen schicke.
Dabei soll das ganze halt Multithreading-Fähig gemacht werden.
Dafür will ich pro erfassten Sensor einen Thread erzeugen.
Die Daten die ich vom Sensor bekomme, die schickt mein Master-Thread/Prozess (der Koordinator) (bin hierbei noch nicht sicher obs ein thread sein soll) an den jeweiligen Worker-Thread.
Frage1:
Die Daten die im jeweiligen Worker-Thread landen müssen visualisiert werden. (z.B. pro Sensor ein TAB im Hauptdialog)
Ist es sinnvoll pro Worker-Thread eine Gui-Thread zu erzeugen oder reicht der einzige std. GUI-Thread?
Frage2:
Die Daten, die vom Worker-Thread angenommen und eventuell bearbeitet worden sind müssen nun visualisiert werden.
Meine Idee war es die zu visualisierenden Daten an die GUI via Signal/Slot zu verschicken und regelmäßig zu updaten (bei Wertveränderungen usw.).
Frage3:
Das ist bezogen auf Frage 1.
Wenn die von mir genannten Worker-Threads keine Rechenaufgaben bekommen, sondern nur Daten bekommen und diese visualisieren müssen. Oder die Daten, die der Benutzer über die GUI eingibt/verändert an die Sensoren zurückgeschickt werden müssen ( ohne etwas zu berechnen).
Sollte man hierbei auf Worker-Threads verzichten und direkt pro Sensor Gui-Threads erstellen?
Stehe gerade etwas auf dem Schlauch bez. Threading.
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Threads lohnen sich:
- wenn du Dinge unabhaengig nebenher machen willst und der prozessor dafuer geeignetmulticore) ist
- wenn eine langwierige taetigkeit schlecht unterbrechbar gestaltbar ist du aber parralel dazu andere teile des programs laufen lassen und steuern willst.
Die Daten der sensoren "aufbereiten" kostet dich doch kaum rechenzeit oder ist das komplex ? nen eigener thread fuer einen sensor wuerde nur lohnen, wenn es da bissi was zu rechnen gibt.
ob man einen thread fuer die sensoren zum auslesen erstellt, um ihn von der gui zu entkoppeln, wuerd ich davon abhaengig machen, was du mit den sensordaten sonst noch machst.
Loggst du die sensordaten, und sind die logs wichtig, genau so wie die genauigkeit der zeitintervalle zwichen den abrufen, wuerde ich schon nen trhead fuers loggen nen thread fuer die sensoren, und den gui thread erstellen.
willst du die sensordaten nur visualisieren, wuerd ich auf multithreading komplett verzichten und alles ueber timer events loesen. macht viel weniger stresss und wenn gui tot nutzen dir die sensordaten ja auch nix mehr ....
Ciao ...
- wenn du Dinge unabhaengig nebenher machen willst und der prozessor dafuer geeignetmulticore) ist
- wenn eine langwierige taetigkeit schlecht unterbrechbar gestaltbar ist du aber parralel dazu andere teile des programs laufen lassen und steuern willst.
Die Daten der sensoren "aufbereiten" kostet dich doch kaum rechenzeit oder ist das komplex ? nen eigener thread fuer einen sensor wuerde nur lohnen, wenn es da bissi was zu rechnen gibt.
ob man einen thread fuer die sensoren zum auslesen erstellt, um ihn von der gui zu entkoppeln, wuerd ich davon abhaengig machen, was du mit den sensordaten sonst noch machst.
Loggst du die sensordaten, und sind die logs wichtig, genau so wie die genauigkeit der zeitintervalle zwichen den abrufen, wuerde ich schon nen trhead fuers loggen nen thread fuer die sensoren, und den gui thread erstellen.
willst du die sensordaten nur visualisieren, wuerd ich auf multithreading komplett verzichten und alles ueber timer events loesen. macht viel weniger stresss und wenn gui tot nutzen dir die sensordaten ja auch nix mehr ....
Ciao ...
Hi,
das aufarbeiten der Sensordaten ist eigentlich nicht komplex.
Es ist aber erwünscht, dass die Threads irgendwann mal "rechnen können".
Die Sensordaten werden noch z.B. geplottet.
Wahrcheinlich (später) noch irgendwelche Kalkulationen.
Die Daten werden, sobald sie anliegen vom Master-Prozess ausgelesen. Der ist sozusagen der Koordinator/ Logger.
Der verteilt die Daten dann an die Threads weiter.
Multithreading wird gefordert, da kommt man nicht drumherum.
Danke für die Antworten.
das aufarbeiten der Sensordaten ist eigentlich nicht komplex.
Es ist aber erwünscht, dass die Threads irgendwann mal "rechnen können".
Die Sensordaten werden noch z.B. geplottet.
Wahrcheinlich (später) noch irgendwelche Kalkulationen.
Die Daten werden, sobald sie anliegen vom Master-Prozess ausgelesen. Der ist sozusagen der Koordinator/ Logger.
Der verteilt die Daten dann an die Threads weiter.
Multithreading wird gefordert, da kommt man nicht drumherum.
Danke für die Antworten.
hmmm ich glaub ich habe was übersehen.
Threads haben ja einen gemeinsamen Speicher.
Meine Worker-Threads würden sich doch gegenseitig stören?!?
Also die Daten gegenseitig überschreiben....
Aus diesem Grund sollte ich doch lieber Prozesse verwenden.
Oder gibt es ein Wunderwerkzeug von QT, damit ein Speicherbereich doch getrennt werden kann?
Threads haben ja einen gemeinsamen Speicher.
Meine Worker-Threads würden sich doch gegenseitig stören?!?
Also die Daten gegenseitig überschreiben....
Aus diesem Grund sollte ich doch lieber Prozesse verwenden.
Oder gibt es ein Wunderwerkzeug von QT, damit ein Speicherbereich doch getrennt werden kann?
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Unter windows ?Aus diesem Grund sollte ich doch lieber Prozesse verwenden.
und selbst unter unix, prozessmanagment iss ned einfach, und um die daten in ne gemeinsame gui zu bekommen brauchst IPC ...
Das wuerd ich mir ned antun
Ich behaupt mal das multithreading bei dir scho bissi overkill waer, man koennt deine Anforderungen auch ohne umsetzen, da waer multiprozessing schon irgendwie mit kanonen auf spatzen ...
Ciao ....
hmm ok, das ist mir irgendwie neu oder ich habe was zuvor verpasst.
Ich war immer der Meinung, immer wenn ich Threads verwende muss ich sie voreinander schützen mit semaphoren oder mutex wie auch immer.
Von Instanzen in Verbindung mit Threads hab ich nie was gesehen/gehört.
Wie wäre denn der Unterschied bei der Erzeugung? (Codebeispiel)
Für mich hört sich die ganze "Instanzsache" so an als ob damit einfach ein neuer Prozess erzeugt wird und kein Thread....
Evtl könnte ich es am Beispiel eines Codeausschnitts besser verstehen.
Danke dir nochmal für die Mühe
Ich war immer der Meinung, immer wenn ich Threads verwende muss ich sie voreinander schützen mit semaphoren oder mutex wie auch immer.
Von Instanzen in Verbindung mit Threads hab ich nie was gesehen/gehört.
Wie wäre denn der Unterschied bei der Erzeugung? (Codebeispiel)
Für mich hört sich die ganze "Instanzsache" so an als ob damit einfach ein neuer Prozess erzeugt wird und kein Thread....
Evtl könnte ich es am Beispiel eines Codeausschnitts besser verstehen.
Danke dir nochmal für die Mühe
Instanz = variable einer klasse/Typ .... grob gesagt.
grob weil es zu allgemein ist, weil variablen selber auch zeiger, referenzen sein koennen, also durchaus 2 variablen auf die selbe Instanz referenzieren koennen.
eigentlich ein lebendes(instanziiertes) Object von einen Typ/Klasse halt ...
von welcher Programmiersprache kommst Du denn ?
Ciao ...
grob weil es zu allgemein ist, weil variablen selber auch zeiger, referenzen sein koennen, also durchaus 2 variablen auf die selbe Instanz referenzieren koennen.
eigentlich ein lebendes(instanziiertes) Object von einen Typ/Klasse halt ...
von welcher Programmiersprache kommst Du denn ?
Ciao ...
schon von C++
, die Aussage hat mich nur etwas irritiert oder ich hab was falsch verstanden. Deswegen diese komische Antwort.
Ich muss kurz meine Gedanken wieder sammeln ...
Wenn ich eine Klasse neu instanziere
x[0] = new Class();
diese ist von Qthread abgeleitet.
Dadurch erzeuge ich automatisch einen Thread.
Den nächsten Thread mit x[1] = new Class() usw....
Soweit so gut
Wenn ich es nun richtig verstanden habe, kann man auch in nur einer Instanz mehrere Threads erzeugen. Wie schaut denn das aus?
Wollte nur die beiden Unterschiede vor Augen habe...mehr nicht
Ich muss kurz meine Gedanken wieder sammeln ...
Wenn ich eine Klasse neu instanziere
x[0] = new Class();
diese ist von Qthread abgeleitet.
Dadurch erzeuge ich automatisch einen Thread.
Den nächsten Thread mit x[1] = new Class() usw....
Soweit so gut
Wenn ich es nun richtig verstanden habe, kann man auch in nur einer Instanz mehrere Threads erzeugen. Wie schaut denn das aus?
Wollte nur die beiden Unterschiede vor Augen habe...mehr nicht
threads haben nichts mit klassen zu tun ...
threads werden vom "System" erzeugt, also man nutzt die API zum system (winapi / windows bzw. Posix bei Linux/Unix ... etc)
diese API's sind meist C .....
Frameworks verhuddeln das meist mit klassen fuer mehr komfort, dafuer weden aber auch details verdeckt.
also generell erzeugst du einen thread aus einem anderen thread heraus.
Beim erzeugen gibst du ihm eine Main procedure als funktionspointer mit, in der der thread startet , sowie eine unspezifizierte variable als context, die alles sein kann ....
das heisst dein thread startet in einer funktion ala void funcXYZ(void * context).
erreicht der thread das ende von funcXYZ ist er auch beendet ....
in der funktionselber hasst du ausser dem context gar nix ... naja und die globalen variablen, aber globale variablen sind ja schmutz.
Also bleibt dem thread nur der context parameter, als Tor zur grossen welt, err zu den daten des programms .... und beim erstellen des threads bestimmst ja, was als parameter genau uebergeben wird, und damit eigentlich was dem thread zur verfuegung steht.
Das ist der C weg .....
QT macht nun folgendes:
Du erstellst eine Instanz von QThread / abgeleite Klasse von QThread.
im Konstruktor wird der thread erzeugt und pausiert .....
einsprungfunktion ist eine statische private memberfunktion(methode) an qthread.
Als context wird gleich ein verweis auf die grade erzeugte instanz (this zeiger im konstruktor) uebergeben ....
mit exec von dem anderen thread aus startest du den thread (resume) ....
in der statischen startmethode wird nix anderes gemacht, als der context zeiger auf QTread gecastet, und an diesem zeiger gleich die methode run aufgerufen ....
Das heisst, fuer dich startet der thread eigentlich gleich mit run() die ja ueberschreiben kannst / sollst .... und die dafuer erzeugte instanz hasst ja gleich zur verfuegung dafuer das in der klasse bist (this zeiger) ....
Das ist natuerlich alles sehr bequem, aber stiftet natuerlich auch werwirrung, da halt viele details der threadprogrammierung im hintergrund laufen ....
WIchtig fuer dich, alle objecte die deine QThread instanz kennt, kennt dann natuerlich der thread, da er die ja ueber den context mit uebergeben bekommt.
Alle member die direkt an qthread haengen, werden von aussen impliziet beim konstruktor erzeugt, und man kommt von aussen ned direkt drauf (datenkapslung).
Da du sicher sein kannst, das die threadproc nie loslaufen wird, bevor die klasse fertig erzeugt wurde (konstructor durchlaufen) brauchst die member nie schuetzen, weil nach der erzeugung nur der thread draufkommt. Oder du schreibst zugriffsfunktionen dafuer, wo dann auch von anderen threads aus zugegriffen werden koennte, ergo -> musst betroffene Daten schuetzen ....
und alles was du lokal in run erzeugst (aufn stack), und ned sharest brauchst natuerlich auch ned schuetzen.
Due kannst deiner Ableitung aber natuerlich auch verweise mitgeben, die musst dann natuerlich schuetzen ....
Also QThread = 1 thread der impliziet erstellt wird.
du kannst in einer instanz natuerlich beliebig viele threads erstellen, und denen sogar unterschiedliche einsprungfunktionen verpassen ....
Macht man z.b. wenn komplexe klassen entkoppeln will und mit nativen c++ abreitet .... also nen thread der eigenstaendig was loggt, nen thread der daten entgegennimmt, nen thread der daten versendet ... etc ... macht manchmal sinn das in einer zu klasse zu bauen ...
unter QT wuerde man das eher anders loesen ... eine Klasse, die mehrere Ableitungen von von qthread instanzieiert (statisch oder dynamisch) , und diese bekommen nen zeiger auf die Instanz in der sie erzeugt wurden.
so koennen dann memberfunktionen von der klasse aus meheren threads aus aufgerufen werden ...
Einigermassen verstaendlich ???
CIao ...
threads werden vom "System" erzeugt, also man nutzt die API zum system (winapi / windows bzw. Posix bei Linux/Unix ... etc)
diese API's sind meist C .....
Frameworks verhuddeln das meist mit klassen fuer mehr komfort, dafuer weden aber auch details verdeckt.
also generell erzeugst du einen thread aus einem anderen thread heraus.
Beim erzeugen gibst du ihm eine Main procedure als funktionspointer mit, in der der thread startet , sowie eine unspezifizierte variable als context, die alles sein kann ....
das heisst dein thread startet in einer funktion ala void funcXYZ(void * context).
erreicht der thread das ende von funcXYZ ist er auch beendet ....
in der funktionselber hasst du ausser dem context gar nix ... naja und die globalen variablen, aber globale variablen sind ja schmutz.
Also bleibt dem thread nur der context parameter, als Tor zur grossen welt, err zu den daten des programms .... und beim erstellen des threads bestimmst ja, was als parameter genau uebergeben wird, und damit eigentlich was dem thread zur verfuegung steht.
Das ist der C weg .....
QT macht nun folgendes:
Du erstellst eine Instanz von QThread / abgeleite Klasse von QThread.
im Konstruktor wird der thread erzeugt und pausiert .....
einsprungfunktion ist eine statische private memberfunktion(methode) an qthread.
Als context wird gleich ein verweis auf die grade erzeugte instanz (this zeiger im konstruktor) uebergeben ....
mit exec von dem anderen thread aus startest du den thread (resume) ....
in der statischen startmethode wird nix anderes gemacht, als der context zeiger auf QTread gecastet, und an diesem zeiger gleich die methode run aufgerufen ....
Das heisst, fuer dich startet der thread eigentlich gleich mit run() die ja ueberschreiben kannst / sollst .... und die dafuer erzeugte instanz hasst ja gleich zur verfuegung dafuer das in der klasse bist (this zeiger) ....
Das ist natuerlich alles sehr bequem, aber stiftet natuerlich auch werwirrung, da halt viele details der threadprogrammierung im hintergrund laufen ....
WIchtig fuer dich, alle objecte die deine QThread instanz kennt, kennt dann natuerlich der thread, da er die ja ueber den context mit uebergeben bekommt.
Alle member die direkt an qthread haengen, werden von aussen impliziet beim konstruktor erzeugt, und man kommt von aussen ned direkt drauf (datenkapslung).
Da du sicher sein kannst, das die threadproc nie loslaufen wird, bevor die klasse fertig erzeugt wurde (konstructor durchlaufen) brauchst die member nie schuetzen, weil nach der erzeugung nur der thread draufkommt. Oder du schreibst zugriffsfunktionen dafuer, wo dann auch von anderen threads aus zugegriffen werden koennte, ergo -> musst betroffene Daten schuetzen ....
und alles was du lokal in run erzeugst (aufn stack), und ned sharest brauchst natuerlich auch ned schuetzen.
Due kannst deiner Ableitung aber natuerlich auch verweise mitgeben, die musst dann natuerlich schuetzen ....
Also QThread = 1 thread der impliziet erstellt wird.
du kannst in einer instanz natuerlich beliebig viele threads erstellen, und denen sogar unterschiedliche einsprungfunktionen verpassen ....
Macht man z.b. wenn komplexe klassen entkoppeln will und mit nativen c++ abreitet .... also nen thread der eigenstaendig was loggt, nen thread der daten entgegennimmt, nen thread der daten versendet ... etc ... macht manchmal sinn das in einer zu klasse zu bauen ...
unter QT wuerde man das eher anders loesen ... eine Klasse, die mehrere Ableitungen von von qthread instanzieiert (statisch oder dynamisch) , und diese bekommen nen zeiger auf die Instanz in der sie erzeugt wurden.
so koennen dann memberfunktionen von der klasse aus meheren threads aus aufgerufen werden ...
Einigermassen verstaendlich ???
CIao ...
danke für deine ausführliche erklärung.
werde es heute abend anhand eines beispielprogramms mal testen.
Code sagt mehr als tausend worte
Falls du ein Codebeispiel rumliegen hast wäre das natürlich auch ganz gut.
Wenn nicht, ist auch kein Problem.
Muss mich mit Threading etwas mehr auseinandersetzen.
Werde meinen Code, hier posten.
Um sicher zu gehen, dass ich es auch richtig verstanden & umgesetzt habe.
danke nochmals
werde es heute abend anhand eines beispielprogramms mal testen.
Code sagt mehr als tausend worte
Falls du ein Codebeispiel rumliegen hast wäre das natürlich auch ganz gut.
Wenn nicht, ist auch kein Problem.
Muss mich mit Threading etwas mehr auseinandersetzen.
Werde meinen Code, hier posten.
Um sicher zu gehen, dass ich es auch richtig verstanden & umgesetzt habe.
danke nochmals
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Hab mir nun ein Beispiel aus dem Buch genommen und damit gearbeitet.
main.cpp
threading.h
threading.cpp
thread.h
thread.cpp
Die Threads schicken aus dem jeweiligen run() ein Signal an das gui-thread damit von da in das listwidget "A" oder "B" eingetragen werden kann. Habe dafür einen Slot getmsg geschrieben.
So wollte ich sehen, wer von den Threads arbeitet.
Die ganze Sache hängt aber ein bisschen, so habe ich das emittieren weggelassen und einfach eine Variable i hochzählen lassen.
Will damit eine nahezu realistische Auslastung simulieren.
Ist da was falsch an meiner Vorgehensweise?
Warum hängt dauernd meine GUI?
EDIT: Ich denke mal, dass beide Sachen einfach zu viel Auslastung verursachen. Habe ein Sleep in run eingeführt. So kann ich sehen, dass die Threads arbeiten.
main.cpp
Code: Alles auswählen
#include <QtGui/QApplication>
#include "threading.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Threading w;
w.show();
return a.exec();
}
threading.h
Code: Alles auswählen
#ifndef THREADING_H
#define THREADING_H
#include <QtGui/QMainWindow>
#include "ui_threading.h"
#include "thread.h"
#include <QtGui/QCloseEvent>
class Threading : public QMainWindow,Ui::ThreadingClass
{
Q_OBJECT
public:
Threading(QWidget *parent = 0, Qt::WFlags flags = 0);
~Threading();
protected:
void closeEvent(QCloseEvent *event);
private:
//Ui::ThreadingClass ui;
Thread threadA,threadB;
private slots:
void getmsg(QString);
void startThreadA();
void startThreadB();
};
#endif // THREADING_H
Code: Alles auswählen
#include "threading.h"
Threading::Threading(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
threadA.setmsg("A");
threadB.setmsg("B");
setupUi(this);
connect(m_starta,SIGNAL(clicked()),this,SLOT(startThreadA()));
connect(m_startb,SIGNAL(clicked()),this,SLOT(startThreadB()));
connect(&threadA,SIGNAL(sendmsg(QString)),this,SLOT(getmsg(QString)));
connect(&threadB,SIGNAL(sendmsg(QString)),this,SLOT(getmsg(QString)));
}
Threading::~Threading()
{
}
void Threading::startThreadA()
{
if(threadA.isRunning()){
threadA.stop();
m_starta->setText("Start A");
}else{
threadA.start();
m_starta->setText("Stop A");
}
}
void Threading::startThreadB()
{
if(threadB.isRunning()){
threadB.stop();
m_startb->setText("Start B");
}else{
threadB.start();
m_startb->setText("Stop B");
}
}
void Threading::closeEvent(QCloseEvent *event)
{
threadA.stop();
threadB.stop();
threadA.wait();
threadB.wait();
event->accept();
}
void Threading::getmsg(QString msg)
{
m_list->addItem(msg);
}
Code: Alles auswählen
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include <QString>
class Thread : public QThread
{
Q_OBJECT
public:
Thread();
~Thread();
void stop();
void setmsg(const QString &msg);
protected:
void run();
signals:
void sendmsg(QString);
private:
volatile bool stopped;
QString message;
};
#endif // THREAD_H
thread.cpp
Code: Alles auswählen
#include "thread.h"
Thread::Thread()
{
stopped = false;
}
Thread::~Thread()
{
}
void Thread::run()
{
int i=0;
while(!stopped)
i++;
// emit sendmsg(message);
stopped = false;
}
void Thread::stop()
{
stopped = true;
}
void Thread::setmsg(const QString &msg)
{
message = msg;
}
So wollte ich sehen, wer von den Threads arbeitet.
Die ganze Sache hängt aber ein bisschen, so habe ich das emittieren weggelassen und einfach eine Variable i hochzählen lassen.
Will damit eine nahezu realistische Auslastung simulieren.
Ist da was falsch an meiner Vorgehensweise?
Warum hängt dauernd meine GUI?
EDIT: Ich denke mal, dass beide Sachen einfach zu viel Auslastung verursachen. Habe ein Sleep in run eingeführt. So kann ich sehen, dass die Threads arbeiten.