Fragen zur Thread-Programmierung
Fragen zur Thread-Programmierung
Hallo,
da ich mich gerade mit Multithreading beschäftige, ein paar Fragen.
Hintergrund ist der: Ich lese Daten von einem CAN2USB-Dongle ein, speichere diese zwischen und lese sie anschließend aus um sie anzeigen zu können. Für diese Aufgabe stelle ich mir zwei Threads vor, welche sich gegenseitig über mutex sperren können.
Meine Fragen im Konkreten:
- was ist genau der Unterschied zwischen run() und exec() und was hat es mit den beiden Funktionen auf sich? Ich habe von Java und anderen echtzeitfähigen Programmiersprachen noch im Hinterkopf, dass sich im Kern jedes Threads eine while(true)-Schleife befindet. Dem ist in den Qt Beispielen allerdings nicht so.
- wie realisiere ich am geschicktesten den Aufruf von QPainter um die Daten zu zeichnen? Bisher habe ich testweise einfach einen Timer herunterlaufenlassen und dann die update()-Funktion aufgerufen. Soll ich weiterhin in dem Thread einfach die update()-Funktion aufrufen? Oder einfach einen neuen im Thread erstellen und dann zeichnen lassen? Hierbei weiß ich allerdings nicht, wie sich Qt verhalten wird, da man ja QPainter immer wieder schließen soll.
- ist es besser die beiden Threads über Signale und Slots zu sychronisieren als über mutex?
Danke für die Antworten,
Thomas
da ich mich gerade mit Multithreading beschäftige, ein paar Fragen.
Hintergrund ist der: Ich lese Daten von einem CAN2USB-Dongle ein, speichere diese zwischen und lese sie anschließend aus um sie anzeigen zu können. Für diese Aufgabe stelle ich mir zwei Threads vor, welche sich gegenseitig über mutex sperren können.
Meine Fragen im Konkreten:
- was ist genau der Unterschied zwischen run() und exec() und was hat es mit den beiden Funktionen auf sich? Ich habe von Java und anderen echtzeitfähigen Programmiersprachen noch im Hinterkopf, dass sich im Kern jedes Threads eine while(true)-Schleife befindet. Dem ist in den Qt Beispielen allerdings nicht so.
- wie realisiere ich am geschicktesten den Aufruf von QPainter um die Daten zu zeichnen? Bisher habe ich testweise einfach einen Timer herunterlaufenlassen und dann die update()-Funktion aufgerufen. Soll ich weiterhin in dem Thread einfach die update()-Funktion aufrufen? Oder einfach einen neuen im Thread erstellen und dann zeichnen lassen? Hierbei weiß ich allerdings nicht, wie sich Qt verhalten wird, da man ja QPainter immer wieder schließen soll.
- ist es besser die beiden Threads über Signale und Slots zu sychronisieren als über mutex?
Danke für die Antworten,
Thomas
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Was ist daran unverständlich?void QThread::run () [virtual protected]
The starting point for the thread.
int QThread::exec () [protected]
Enters the event loop ...
Zu dem anderen Problem - wie sollte das mit Signals/Slots überhaupt funktionieren?
MfG Christian
'Funktioniert nicht' ist keine Fehlerbeschreibung
'Funktioniert nicht' ist keine Fehlerbeschreibung
wenn ich die Funktion run() neu implementiere, ohne ein exec() hineinzuschreiben - was passiert dann? Habe ich einen Thread ohne Schleife? Was genau bedeutet event loop?
Ansonsten dachte ich an ein gegenseitiges Aufrufen zweier Funktionen - sobald die erste geschrieben hat wird ein Signal gesendet damit die zweite auslesen kann...
Thomas
Ansonsten dachte ich an ein gegenseitiges Aufrufen zweier Funktionen - sobald die erste geschrieben hat wird ein Signal gesendet damit die zweite auslesen kann...
Thomas
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Wenn Du keine Event-Loop in deinem Thread hast, wird es auch nichts mit signals und slots --> mal wieder Verweis auf die Doku und Examples ( http://doc.trolltech.com/4.4/threads.html )
Für deine Synchronisation - das geht natürlich auch mit Signals/Slots, aber dafür brauche ich nicht unbedingt einen extra-Thread.
Für deine Synchronisation - das geht natürlich auch mit Signals/Slots, aber dafür brauche ich nicht unbedingt einen extra-Thread.
MfG Christian
'Funktioniert nicht' ist keine Fehlerbeschreibung
'Funktioniert nicht' ist keine Fehlerbeschreibung
Wegen der Geschichte ein Thread darf erst was machen wenn der zweite fertig ist und damit auch etwas bereitstellt womit der erste Thread was anfangen kann, suchst Du wahrscheinlich das Design Pattern Semaphore, Beispiel mit Qt: http://doc.trolltech.com/4.4/threads-semaphores.html
Die Synchronisierung wie Du sie aus Java kennst ist aber etwas anderes, da geht es mehr darum eine Methode "Thread-Safe" zu machen, also alle anderen Threads müssen warten bis ein Thread der sich gerade "in" der Methode befindet fertig ist um so zu verhindern das 2 Threads zur "selben" Zeit Daten unterschiedlich verarbeiten. Das erreichst Du mit QMutex und QWaitCondition
Gut Schuß
VuuRWerK
Die Synchronisierung wie Du sie aus Java kennst ist aber etwas anderes, da geht es mehr darum eine Methode "Thread-Safe" zu machen, also alle anderen Threads müssen warten bis ein Thread der sich gerade "in" der Methode befindet fertig ist um so zu verhindern das 2 Threads zur "selben" Zeit Daten unterschiedlich verarbeiten. Das erreichst Du mit QMutex und QWaitCondition
Gut Schuß
VuuRWerK
Es gibt nur 3 natürliche Feinde des Programmierers: Tageslicht, frische Luft und das unerträgliche Gebrüll der Vögel.
Oft ist die Ursache des schwarzsehens lediglich ein verrutschen des Bretts vorm Kopf =)
Oft ist die Ursache des schwarzsehens lediglich ein verrutschen des Bretts vorm Kopf =)
Dann wird die run() wieder verlassen und an dem Punkt weitergemacht, wo der besagte Thread gestartet wurde.wenn ich die Funktion run() neu implementiere, ohne ein exec() hineinzuschreiben - was passiert dann? Habe ich einen Thread ohne Schleife?
Wenn mit exec() die Thread Eventloop gestartet wird, "lebt" der Thread dann noch und kann mit signals / slots bedient werden. Wenn die Eventloop beendet wird, hätte man die Möglichkeit, den "returnCode" in der run() auswerten zu lassen und falls auch dann keine weiteren Anweisungen in der run() vorhanden sind, wird diese dann auch verlassen.
Vielleicht hilfts ja besser zum Verständnis. Aber wie die Anderen schon sagten: Qt Assistent lesen, der wirlklich top ist / oder auch mal die Examples / Qt Demos laufen lassen...
Wichtig ist aber auch noch, dass man sich Gedanken darum macht, wo genau Objekte in welchem Thread "leben", sag ich mal. Dazu verweis ich direkt mal auf die Doku zur Klasse QObject.
Gruß
-
Superheftig
- Beiträge: 63
- Registriert: 6. September 2008 15:20
Der Event Loop von qt bewirkt bewirkt dass der thread nachrichten empfangen kann und wird mit exec gestartet.
Wenn du die run() methode im Thread nicht überschreibst sieht das ganze standardmäßig so aus
Der Event Loop wird also sofort aufgerufen. Der EventLoop blockiert den Code an dieser stelle, ist also so eine art while(true) konstruktion. wenn du den thread mit exit() stoppst wird diese schleife durchbrochen und der code kehrt in die run medthode zurück.
Wenn du die run methode überschreibst und du das Event Managment von qt braucht muss der letzte aufruf in deiner run Methode exex() sein. Sonst ist es dem Thread nicht möglich nachrichten zu empfangen, also
Im normalfall brauchst du allerdings das exec() garnicht. Dann kannst du deinen eigenen loop machen, also
Alles was mit Fenstern und zeichnen zu tun hat kannst du nur im main Thread wie oben erwähnt. Also startest du einfach aus dem mainthread den thread der die daten von usb ausliehst und übergibst ihm ne Queue als pointer. Auf die Queue haben dann beide Threads zugriff darum schützt du jeden zugriff durch einen Mutex.....Fertig!
Signals und Slots brauchst du also garnicht
Wenn du die run() methode im Thread nicht überschreibst sieht das ganze standardmäßig so aus
Code: Alles auswählen
void run() {
exec();
}Wenn du die run methode überschreibst und du das Event Managment von qt braucht muss der letzte aufruf in deiner run Methode exex() sein. Sonst ist es dem Thread nicht möglich nachrichten zu empfangen, also
Code: Alles auswählen
void run() {
/*
Thread initialisierung
Code hier
*/
exec()
}Code: Alles auswählen
void run() {
while(true) {
// Daten vom usb auslesen und in queue speichern
// falls keine Daten vorhanden sind sleep(10);
}
}Signals und Slots brauchst du also garnicht
Hallo,
mittlerweile bin ich soweit, dass ich das Einlesen zyklisch als Thread ausführe und alle 100ms ein Signal zum Weiterrechnen/Zeichnen schicke. Das Rechnen/Zeichnen ist jedoch nicht als Thread ausgeführt. Was passiert wenn er nun rechnet? blockiert er hierbei den Einlesethread (weil es selber ja keiner ist)?
Thomas
P.S. sehe ich es rihtig das lediglich die Argumente, welche in run() stehen, als Thread ausgeführt werden, andere Funktionen (auch wenn sie sich in derselben Klasse befinden) jedoch nicht?
mittlerweile bin ich soweit, dass ich das Einlesen zyklisch als Thread ausführe und alle 100ms ein Signal zum Weiterrechnen/Zeichnen schicke. Das Rechnen/Zeichnen ist jedoch nicht als Thread ausgeführt. Was passiert wenn er nun rechnet? blockiert er hierbei den Einlesethread (weil es selber ja keiner ist)?
Thomas
P.S. sehe ich es rihtig das lediglich die Argumente, welche in run() stehen, als Thread ausgeführt werden, andere Funktionen (auch wenn sie sich in derselben Klasse befinden) jedoch nicht?
-
Superheftig
- Beiträge: 63
- Registriert: 6. September 2008 15:20
Du hast automatisch den main Thread und deinen Auslese Thread. Das Zeichnen/Rechnen blockiert also das auslesen nicht.
Alle funktionen werden von dem Thread ausgeführt von dem sie aufgerufen werden. Wenn du also eine Funktion die in deinem AusleseThread implementiert ist von außerhalb aufrufst, also z.b aus deiner Zeichnen/Rechnen Funktion, dann läuft die Funktion auch in diesem Thread. Dieses sollte man allersings unterlassen, da bei eingigen QT Klassen das verhalten ungewiss ist.
Warum und Welche steht in der Doku
Alle funktionen werden von dem Thread ausgeführt von dem sie aufgerufen werden. Wenn du also eine Funktion die in deinem AusleseThread implementiert ist von außerhalb aufrufst, also z.b aus deiner Zeichnen/Rechnen Funktion, dann läuft die Funktion auch in diesem Thread. Dieses sollte man allersings unterlassen, da bei eingigen QT Klassen das verhalten ungewiss ist.
Warum und Welche steht in der Doku
@nierth
Dir fehlt es noch ein bisserl an Verstaendniss zu den Threads. Du solltest mal versuchen, nen "Thread" mit der winapi zum laufen zu bekommen, ohne QThread ... dann verstehst du auch besser was welche Methode in QThread macht und in welchem thread sie lebt.
QThread repraesentiert nicht ein Thread, wie man es anhand des namens vielleicht annehmen koennte, sondern implementiert das Thread haendling, also viele funktionen rund um das erzeugen und Steuern des Threades.
Naruerlich werden alle aufrufe von deiner run() methode aus dann in dem thread ausgefuehrt, egal welche methode von welcher klasse das ist.
wichtig ist, das du folgendes verstehst:
signale und slots werden ueber die Eventloop synchronisiert, in dessen Context das Object mit den Slots laeuft.
Dabei laufen alle Objecte im Context der Application (QApplication) und nur Objecte die eine eigene Eventloop starten koennen (QThread::exec() z.b.) , koennen aus diesem context wechseln. Die Eventloop lauft natuerlich in dem threrad, in dem sie gestartet wurde, also sollt man wenn man parralelle eventloops haben will, die 2. loop in nem eigenen thread starten, (deshalb im run() ausgefuehrt).
Startet man 2 eventloops im selben thread, wird nur die zueletzt aufgerufene bearbeitet, und erst wenn die beendet wird, gehts in der alten weiter. In einigen faellen wird dies verwendet (Modelitaet) ....
- bei signalen und slots ueber slots werden die parameter wie bei jeder funktion kopiert. Bei queued connections wirden die parameter mit in die eventloop kopiert und irgendwann spaeter ausgefuehrt.
Normal verwendest da eigentlich impliziet immer kopien, was das ganze in sachen threadsicherheit etc ziemlich einfach macht.
Verwendest du da zeiger und referenzen, musst du sicherstellen das die
a. geschutzt sind und b, atuerlich noch existieren, wenn die eventloop die dinger abarbeitet.
du kannst in deinem thread ohne eventloop signale correct emitten, mit einem postevent werden die korrect in die eventloop deines Mainthreads der QApplication eingetragen, und dein Slot wird auch angsprungen ....
Also mit QThread und ohne eigene Loop kannst nur signale zum mainthread schicken, aber keine vom maintread empfangen ....
Selber synchroniseren macht Sinn wenn man viele datenmengen bekommt und die ned kopieren will ... ausserdem ist der eventmechanismus ziemlich generisch und damit ned wirklich schnell ...
Mit einem Can Adapter wirst sicherlich performancetechnisch keine probleme haben ....
Selbst mit 4 Highspeed CAN's (500kbit) parrallel hier langweilt sich der rechner ...
Aber hab mal Flexray und Most, da siehts schnell anders aus ... und dann wird man sich um performance gedanken machen müssen.
Ciao ...
Dir fehlt es noch ein bisserl an Verstaendniss zu den Threads. Du solltest mal versuchen, nen "Thread" mit der winapi zum laufen zu bekommen, ohne QThread ... dann verstehst du auch besser was welche Methode in QThread macht und in welchem thread sie lebt.
QThread repraesentiert nicht ein Thread, wie man es anhand des namens vielleicht annehmen koennte, sondern implementiert das Thread haendling, also viele funktionen rund um das erzeugen und Steuern des Threades.
Ja, nur Deine überschriebene run() methode wird initial in deinem neuen thread ausgefuehrt, wenn die run methode zu ende (also du den scope der funktion verlaesst) ist, ist dein thread beendet, und wird auch vom system freigegeben (das thread handle wird ungültig) .P.S. sehe ich es rihtig das lediglich die Argumente, welche in run() stehen, als Thread ausgeführt werden
Naruerlich werden alle aufrufe von deiner run() methode aus dann in dem thread ausgefuehrt, egal welche methode von welcher klasse das ist.
Das ist ne ziemlich komplexe frage und nicht mit einem einfachen ja oder nein zu beantworten.- ist es besser die beiden Threads über Signale und Slots zu sychronisieren als über mutex?
wichtig ist, das du folgendes verstehst:
signale und slots werden ueber die Eventloop synchronisiert, in dessen Context das Object mit den Slots laeuft.
Dabei laufen alle Objecte im Context der Application (QApplication) und nur Objecte die eine eigene Eventloop starten koennen (QThread::exec() z.b.) , koennen aus diesem context wechseln. Die Eventloop lauft natuerlich in dem threrad, in dem sie gestartet wurde, also sollt man wenn man parralelle eventloops haben will, die 2. loop in nem eigenen thread starten, (deshalb im run() ausgefuehrt).
Startet man 2 eventloops im selben thread, wird nur die zueletzt aufgerufene bearbeitet, und erst wenn die beendet wird, gehts in der alten weiter. In einigen faellen wird dies verwendet (Modelitaet) ....
- bei signalen und slots ueber slots werden die parameter wie bei jeder funktion kopiert. Bei queued connections wirden die parameter mit in die eventloop kopiert und irgendwann spaeter ausgefuehrt.
Normal verwendest da eigentlich impliziet immer kopien, was das ganze in sachen threadsicherheit etc ziemlich einfach macht.
Verwendest du da zeiger und referenzen, musst du sicherstellen das die
a. geschutzt sind und b, atuerlich noch existieren, wenn die eventloop die dinger abarbeitet.
Das ist natürlich nur halb richtig ....Wenn Du keine Event-Loop in deinem Thread hast, wird es auch nichts mit signals und slots
du kannst in deinem thread ohne eventloop signale correct emitten, mit einem postevent werden die korrect in die eventloop deines Mainthreads der QApplication eingetragen, und dein Slot wird auch angsprungen ....
Also mit QThread und ohne eigene Loop kannst nur signale zum mainthread schicken, aber keine vom maintread empfangen ....
Selber synchroniseren macht Sinn wenn man viele datenmengen bekommt und die ned kopieren will ... ausserdem ist der eventmechanismus ziemlich generisch und damit ned wirklich schnell ...
Mit einem Can Adapter wirst sicherlich performancetechnisch keine probleme haben ....
Selbst mit 4 Highspeed CAN's (500kbit) parrallel hier langweilt sich der rechner ...
Aber hab mal Flexray und Most, da siehts schnell anders aus ... und dann wird man sich um performance gedanken machen müssen.
Ciao ...