[gelöst]QThread finished Signal wird nicht ausgelöst

Alles rund um die Programmierung mit Qt
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Das moveToThread im ctor bringt gar nichts (zum x. Mal). Es muss in die run() - Methode da nur dort der neu erzeugte Thread läuft!
Da Du dies nicht machst wird auch der wiederholen() - Slot im Hauptthread ausgeführt. this ist ja immer noch im Hauptthread also ...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Alex66955
Beiträge: 56
Registriert: 23. September 2009 14:48

Beitrag von Alex66955 »

Christian81 hat geschrieben:Das moveToThread im ctor bringt gar nichts (zum x. Mal). Es muss in die run() - Methode da nur dort der neu erzeugte Thread läuft!
Da Du dies nicht machst wird auch der wiederholen() - Slot im Hauptthread ausgeführt. this ist ja immer noch im Hauptthread also ...
Das Problem ist eben das es hängt wenn es auserhalb vom Konstruktor ist.

Wenn ich es in die Run- Methode mache --> hängt die Gui

Code: Alles auswählen

void Thread::run(){
    this->moveToThread(this);
    isClose=false;
    noneThread = new NonThread();
    connect(noneThread, SIGNAL(senden()), this, SLOT(wiederholen()), Qt::QueuedConnection);
    exec();
}

Thread::Thread(){
}

void Thread::wiederholen(){
    qDebug() << "Wiederholen";
    if(isClose){
        this->quit();
        return;
    }
    this->sleep(2);
    noneThread->sendenbegin();
}

void Thread::requestClose(){
    qDebug() << "request close";
    isClose= true;
}


Thread::~Thread(){
      qDebug() << "thread gelöscht";
      noneThread->deleteLater();
}

AUSGABE:
QObject::moveToThread: Current thread (0x3e4ed0) is not the object's thread (0x9527e88).
Cannot move to target thread (0x9527e88)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Christian81 hat geschrieben:Das moveToThread im ctor bringt gar nichts (zum x. Mal). Es muss in die run() - Methode da nur dort der neu erzeugte Thread läuft!
Da Du dies nicht machst wird auch der wiederholen() - Slot im Hauptthread ausgeführt. this ist ja immer noch im Hauptthread also ...
Entweder bin ich komplett übermüdet oder du liegst (ausnahmsweise) falsch. Bei moveToThread muss der aktuelle Thread(-Kontext) und die Threadzugehörigkeit gleich sein. Diese Bedingung ist ausserhalb der run-Methode erfüllt. Beispiel:

Code: Alles auswählen

  MyThread *t = new MyThread()
  
  // Aktueller Kontext ist der main-Thread ("GUI")
  // Aktuelle Zugehörigkeit von t ist der Eventloop der GUI
  t->moveToThread(t); // Verschiebe Instanz t in den Eventloop von t. OK
Das gleiche bewirkt natürlich auch ein "moveToThread(this)" im CTor. Es spielt keine Rolle ob diese Methode im CTor oder gleich danach aufgerufen wird.

Jedoch:

Code: Alles auswählen

  void MyThread::run() 
  {
      // aktueller Kontext ist t
      // aktuelle Zugehörigkeit von t ist der GUI-Thread, daher:
      moveToThread(this); // illegal, weil "it cannot "pull" an object from any arbitrary thread to the current thread."
      ..
  }

Zu den anderen Problemen:

Warum Blockade ohne "moveToThread":
Wenn ich diesen Befehl im Konstruktor weglasse wird die Gui Blockiert. Mir ist aber nur halb klar warum. Ich nehme an das durch das aufrufen der Unterklasse der Kontext im MainThread liegt und deswegen die Gui Blockiert. Also notwendig??
Das ist doch ganz logisch:
* Die Instanz von "Thread" lebt ohne moveToThread im GUI-Thread
* Die Instanz von "NonThread" lebt in "Thread".
* Wenn also NonThread ein Signal an "Thread" absetzt, wird dieses im Hauptthread verarbeitet:

Code: Alles auswählen

  int main(...)
  QApplication app....

  app.exec(); // HIER
Daher blockiert die GUI.

Warum Memoryleack MIT moveToThread:
--> Funktioniert jedoch nicht! Sprich Boolean wird gesetzt aber kein finished() Signal gesendet bzw Destruktor aufgerufen.
Auch das ist doch vollkommen logisch:
* mit moveToThread im CTor verarbeitet die Instanz von "Thread" alle Events im eigenen Eventloop:

Code: Alles auswählen

  void Thread::run() 
  {
    ...
    exec(); // HIER
  }
Gerade wenn diese Methode verlassen wird (durch quit()),wird auch das Signal "finished()" abgesetzt. Dieses hast du nun mit "deleteLater()" als QueuedConnection verbunden, das heisst der Auftrag wird im eigenen Eventloop hinterlegt (gerade der, der beendet wird!!!).
Ich habe es nicht getestet, aber ich vermute ein "moveToThread(QApplication::instance()->thread());" gleich nach "exec()" bringt auch nichts mehr (Doku: Note that any new events that are posted to this object will be handled in the targetThread., da steht nichts von den alten "pending" Events..).

Daher: ein Thread welcher bei sich selbst lebt kann kein Selbstmord begehen. Du wirst in der GUI auf das "finished()"-Signal reagieren und dort den Thread löschen müssen.

Weiters: Wenn du von Adam und Eva beginnst und momentan gerade die Architektur festlegt, solltest du unbedingt gut durchlesen: Blog You're doing it wrong


hth.

[EDIT]

Code: Alles auswählen

Thread::~Thread(){
      qDebug() << "thread gelöscht";
      noneThread->deleteLater();
} 
Das ist sowieso für die Katz: der Löschauftrag wird im Eventloop des Threads hinterlegt, welcher jedoch schon lange mit "quit()" verlassen wurde... Die Instanzen des Threads solltest du VOR dem Verlassen löschen...
Zuletzt geändert von solarix am 24. August 2010 12:46, insgesamt 1-mal geändert.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Den Thread kennt er schon - hilft nur nichts.

Und mit dem moveToThread hast Du recht. Habe mir gerade den Sourcecode mal angeschaut. Das verwirrt aber den geneigten Anfänger noch mehr *grml*
Mein Standpunkt war dass der Thread ja erst innerhalb der run() - Methode existiert. Deshalb dürfte ein moveToThread() im ctor nicht funktionieren. Ein moveToThread macht aber nichts mit dem Thread sondern ist quasi nur eine Zuweisung zu einem QThread-Objekt - egal ob der Thread schon vorhanden ist, existiert oder schon tot ist. Dessen war ich mir nicht bewusst. Und deshalb funktioniert es schon im ctor und man kann, wie Du sagtest ein QObject nur von seinen aktuellen in einen anderen QThread schieben, nicht andersrum :(
Dafür muss ich noch'n Bier trinken ... shit :roll:

/edit: Und das schlimmste ist... ich glaube ich habe es an einer Stelle auf Arbeit genau so falsch gemacht wie ich oben behauptete... *argh*
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Christian81 hat geschrieben:[...]Ein moveToThread macht aber nichts mit dem Thread sondern ist quasi nur eine Zuweisung zu einem QThread-Objekt - egal ob der Thread schon vorhanden ist, existiert oder schon tot ist.
[...]
Exakt.. falls es dich beruhigt: ein Artikel im Linux-Magazin vor ein paar Wochen über genau dieses Thema war auch Schrott..
Christian81 hat geschrieben: /edit: Und das schlimmste ist... ich glaube ich habe es an einer Stelle auf Arbeit genau so falsch gemacht wie ich oben behauptete... *argh*
Naja, bis jetzt scheint's niemand bemerkt zu haben :wink:
Christian81 hat geschrieben: Dafür muss ich noch'n Bier trinken
Jetzt erzähl uns bloss nicht, dass das eine Strafe für dich wäre :P
Alex66955
Beiträge: 56
Registriert: 23. September 2009 14:48

Beitrag von Alex66955 »

Danke für die Antworten und den Link, hat mich weitergebracht.

Habe jetzt eine Worker Klasse Implementiert und diese mit moveToThread dem thread hinzugefügt. Dann hatte ich noch die Probleme das der Konstruktor der Worker Klasse im Thread der Main Applikation war.. Eine richtige Lösung dafür habe ich nicht gefunden aber durch implementierung der wichtigsten funktionen außerhalb des Konstruktors konnte ich das Problem übergehen.

Gruß Alex
Antworten