[gelöst]QThread in Qt4.4

Alles rund um die Programmierung mit Qt
Antworten
ColonelMoW
Beiträge: 30
Registriert: 15. April 2008 16:24

[gelöst]QThread in Qt4.4

Beitrag von ColonelMoW »

Guten Abend.

Ich musste aufgrund eines Bugs in der TableView in Verbindung mit Sortierung von QT4.3 auf QT4.4 umsteigen. Bisher hat auch alles sehr gut
funktioniert, bis ich meinen Thread-Teil nochmal testen wollte. Ploetzlich
kann ich auf Objekte welche innerhalb der run() erstellt worden sind, vom Thread aus nicht mehr zugreifen.
Hier ein Beipsiel

mythread.h:

Code: Alles auswählen

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QTimer>
#include <QDebug>

class MyThread : public QThread
{
   Q_OBJECT
public:
   MyThread(QObject *parent = 0) : QThread(parent){}
   ~MyThread(){ delete timer;}
   
   void run(void)
   {
      qDebug() << "head of run";
      timer = new QTimer;
      timer->setSingleShot(true);
      timer->setInterval(1000);
      
      connect( timer, SIGNAL(timeout()), this, SLOT(restartTimer()));
      
      timer->start();
      
      qDebug() << "about to start event loop";
      exec();
      
   }
   
private slots:
   void restartTimer(void)
   {
      timer->start();
      qDebug() << "Timer restarted";
   }
   
private:
   QTimer *timer;
};

#endif //MYTHREAD_H

main.cpp:

Code: Alles auswählen

#include <QtGui>
#include "mythread.h"
 

int main(int argc, char* argv[])
{
   QApplication app(argc, argv);
   
   MyThread thread;
   thread.start();
   
   return app.exec();
}

Hier die Ausgaben:
head of run
about to start event loop
QObject::startTimer: timers cannot be started from another thread
Timer restarted

Kann das vielleicht mal jemand bei sich testen, ob das an meiner Version liegt, oder ob ich vollkommen auf dem Schlauch steh...

waere echt klasse

Col
Zuletzt geändert von ColonelMoW am 2. Juni 2008 16:07, insgesamt 1-mal geändert.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Ich fahre hier einen 4.4.1er Snapshot unter Linux und bekomme keine derartigen Fehlermeldungen...
keeney
Beiträge: 9
Registriert: 14. September 2007 01:56
Wohnort: Regensburg
Kontaktdaten:

Beitrag von keeney »

Ich bekomm hier die Fehlermeldung unter Qt4.4.0/MacOSX auch nicht, aber mit Qt4.3.x. Und irgendwie erscheint nach meinem Verstaendnis die Fehlermeldung auch logisch, denn dein QTimer Object gehoert zum Main Event Loop (dort hast du es angelegt), und dein MyThread bekommt durch exec() einen eigenen Event Loop, in dem du dann versuchst, auf QTimer aus dem Main Event Loop zuzugreifen, und das ist nicht erlaubt.

In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.
Warum sich das in Qt4.4.0 einmal so, einmal so verhaelt, weiss ich nicht, ist mir aber bzgl Threads schon an anderen Stellen aufgefallen.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hatte unter Qt 4.3.4/Win zunächst das selbe Problem.

Hier die Lösung:

Code: Alles auswählen

connect( timer, SIGNAL(timeout()), this, SLOT(restartTimer()),Qt::DirectConnection);
Mit "Qt::DirectConnection" klappts.


Ciao,
Sephral
ColonelMoW
Beiträge: 30
Registriert: 15. April 2008 16:24

Beitrag von ColonelMoW »

Oh ihr habt ja alle so recht.... Wie konnte ich denn nur...

Aus irgendeinem Grund war ich der Ansicht, dass die Objekte der von QThread abgeleiteten Klasse dem Thread gehoeren. Das ist natuerlich NICHT so!...
Ich habe dann nach langem Suchen die Loesung hier gefunden:
http://www.qtforum.de/forum/viewtopic.p ... connection
und auch in der Doku (wenn man weiss nach was mach sucht, dann findet man es schon ;) )

Ich hatte eine Klasse die von QThread abgeleitet war. Diese war ein Server und die Instanz hatte einen Socket, einen Timer, etc. Qt 4.3 war da noch gnaedig und hat mich den Timer starten, den socket bedienen, etc. lassen. Das war natuerlich trotzem mein Fehler. Qt 4.4 ist da offensichtlich etwas strenger (zum Glueck!)

Ich habe jetzt alles in eine QObject-Klasse gepackt die dann in der run() auf dem Stack instantiiert wird. Und es geht wieder wunderbar.

Danke an upsala, keeney und natuerlich auch Sephral.

Col
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hiho,

Du hast doch schon Dein Objekt (new QTimer).
Ich habe Dein Beispiel gerade mal erweitert (mit meiner Änderung) und habe die Threads in eine Endlosschleife geschickt im restartTimer-Slot. Dann das Ganze auf 5 parallele Threads erweitert.

Alle Threads liefen ordentlich in Ihrer Endlosschleife (die durch den Timer angesprungen wurde) und haben Debugausgaben produziert.

Dir fehlte also nur das "Qt::DirectConnection"...oder übersehe ich etwas?

Ciao,
Sephral
ColonelMoW
Beiträge: 30
Registriert: 15. April 2008 16:24

Beitrag von ColonelMoW »

Das Stimmt schon mit der DirectConnection. Dann wird der Slot ebenfalls im Thread des Timers ausgefuehrt.
Das war aber auch nur ein Beispiel. In meiner Server Anwendung muss der Worker-Thread mittels Signal, Daten ueber einen Socket eines anderen Threads versenden. Da geht keine DirectConnection.
Wie sich herausgestellt hatte gehoeren die Slots des QThread-Objektes eben nicht zum Thread der run()-Routine, sondern zu dem Thread der das QThread-Objekt instantiiert hatte. Ergo ich darf von diesen Slots aus nicht auf das Socket-Objekt der run()-Routine zugreifen. Es steht ja auch in der Doku drin, aber ich habe das irgendwie nicht wahrgenommen.

Trotzem vielen Dank fuer deinen Muehen!

Col
Antworten