QT Thread (Methode im falschen Thread



  • Hallo,

    ich habe eine Klasse geschrieben, die von QThread erbt. Nun ist das Problem, dass sich das Programm in einer Methode im falschen Thread befindet.

    Und zwar gibt:
    this->thread() den Thread der Klasse aus
    QThread::currentThread() jedoch den MainThread

    Das Ganze wurde in der Methode aufgerufen, die in der Thread Klasse implementiert wurde. Wie kann ich sagen, das diese Methode in dem Thread der Klasse ausgeführt werden soll?


  • Mod

    Evtl. hilft dir dieser Blogbeitrag weiter:
    http://labs.trolltech.com/blogs/2010/06/17/youre-doing-it-wrong/



  • Hallo,

    ich habe das jetzt in der tat so gelöst, dass ich QThread gesubclassed habe. Weil ich das auch so der Doku entnommen habe. Ist das nun gänzlich nicht so gewollt? Hier mal mein Code Ausschnitt:

    MyThread::MyThread() {
    
        this->moveToThread(this);
        object = new Object();
        object->moveToThread(this);
    }
    
    void MyThread::method() {
    
        qDebug() << this->thread();
        qDebug() << QThread::currentThread();
        qDebug() << qApp->thread();
    
        //Etwas mit object tun...
    
    }
    

    In der Methode method ist das Programm im "falschen Thread".



  • Threader schrieb:

    In der Methode method ist das Programm im "falschen Thread".

    Wer ruft method wann und wie auf? Ein "moveToThread" hängt nämlich nur das Event-Processing an den angegebenen Thread, das Objekt selber kannst du nicht verschieben. Wenn du method() direkt aus dem Hauptthread heraus aufrufst, wird die Methode im Kontext des Aufrufenden Threads gestartet (ist immer so, nicht nur bei Qt) - das ist hier der Main-Thread.
    Wenn du method() in run() aufrufst, sollte auch currentThread() das erwartete ausgeben.



  • Die Methode wird aus dem Hauptthread aufgerufen. Ich habe mir schon gedacht, dass es damit zusammen hängt. Nur wie kann ich sie aus dem Thread aufrufen? In der Run Methode habe ich eigentlich nur ein exec(); für die eventloop. Und es soll möglich sein die Methode aufzurufen, wenn diese schon gestartet ist.



  • Wenn du in run() nur exec() stehen hast, brauchst du gleich gar nicht ableiten, denn genau das steht auch schon in der default-Implementierung von run().
    Pack die method()-Methode in die Worker-Klasse, verschieb sie ein ein QThread-Objekt (nicht abgeleitet), starte den Thread. Aufrufen über SIGNAL/SLOT, verbunden mit QueuedConnection. Steht doch in dem Blog wie man es machen sollte.



  • Könntest du das mal bitte schemenhaft vormachen? Also ich habe eine Worker Klasse. Diese besitzt ein QThread Objekt? Also so richtig ist mir das noch nicht klar.



  • Ein bisschen Kommentare lesen (ist doch logisch, dass da einige Probleme mit haben) und du bekommst nen Link, wo ein Beispiel verlinkt ist 😛
    http://chaos.troll.no/~bhughes/producerconsumer2.tar.gz



  • Ja das habe ich in den Kommentaren gelesen. Aber bei mir ist das Problem denke ich ein klein wenig anders.

    Hier nochmal mein Komplettes Szenario.

    Ich habe eine Klasse für Mein HauptFesnter, also die GUI. Dann eine Klasse, die jetzt der Thread war. In dieser Thread Klasse wird das Objekt object erzeugt, was eine EventQueue nutzt. Diese soll auch im seperaten Thread arbeiten. Genau so wie alle Methoden der Thread Klasse.

    Die Methoden sollen aus der HauptFenster Klasse aufgerufen werden. Wie kann ich das nun gestalten? Ich würde jetzt der GUI Klasse ein Thred objekt geben. In der GUI Klasse wird dann im Konstruktor ein Objekt der ehemaligen Thread Klasse angelegt und ein QThread Objekt erzeugt. Das Thread Klassenobjekt wird dann mit movetothread dem QThread Objekt zugewiesen.

    Oder ist die Denkweise falsch?


  • Mod

    Du solltest mit einem anderen Thread das Event System/Signal/Slot zur Kommunikation nutzen.
    Ein direkter Aufruf einer Methode führt nur dazu, das sie im selben Threadcontext ausgeführt wird.



  • Das Objekt lebt in dem Thread, in dem es erzeugt wurde. Ist nicht nur in Qt so, sondern immer und überall. Du musst dich jetzt von dem Gedanken befreien, dass "QThread == Thread"! QThread ist eine Klasse, die dir das Arbeiten mit Threads in der Qt-Umgebung vereinfachen soll. Ein Thread ist immer Systemspezifisch.
    QThread::start() ruft die run()-Methode nun in so einem Systemspezifischen Thread auf. run() ist also die einzige Möglichkeit, Objekte tatsächlich in einem anderen Thread zu erzeugen! Alles was du in run() machst, geschieht in einem neuen Thread.

    Was macht dann moveToThread? Das schiebt das Eventhandling deines QObjects in den neuen Thread. Das Objekt selber liegt aber nicht in dem neuen Thread, sondern dort, wo es erzeugt wurde.

    Methodenaufrufe werden immer in dem Thread abgearbeitet, in dem sie geschehen.

    // Wir befinden uns im MainThread:
    QThread thread;
    thread.start();
    MyObject obj;
    obj.moveToThread(&thread);
    obj.methode(); // Dieser Methodenaufruf wird nun im MainThread laufen! Dauert er lange blockiert die Gui!
    

    Damit du nun solche Methodenaufrufe garantiert in den anderen Thread bekommst, musst du die EventLoop dazu nutzen. Entweder triggerst du ein SIGNAL, das auf einen SLOT in obj verbunden ist, oder du nutzt QMetaObject::invokeMethod, mit Qt::QueuedConnection als ConnectionType. Dann läuft der SLOT-Aufruf über die EventLoop, die ja bekanntermaßen (moveToThread()) im neuen Thread werkelt (thread.start(); ).



  • Mein Problem ist es ja jetzt, dass ich in der Klasse, die im MainThread erzeugt wird noch ein Objekt erzeuge, dessen EventQueue auch im neuen Thread ablaufen soll hier nochmal ein Überblick:

    MainWindow:

    MainWindow::MainWindow() {
        setupUi(this);
    
        thread = new QThread();
        thread->start();
        myclass = new MyClass();
        myclass->moveToThread(thread);
    
    }
    

    MyClass:

    MyClass::MyClass() {
    
        object = new Object();
    }
    
    void MyClass::method() {
    //mache was mit object
    }
    

    Dieses Object soll im neuen Thread werkeln, also EventQueue etc. Und die ganzen Methoden aus MyClass.
    Muss ich da jetzt doch MyClass von QThread erben lassen, und das Objekt object in der Run methode erzeugen?



  • Ich habe es jetzt erst mal so gelöst: aber ka, ob das optimal ist:

    MainWindow::MainWindow() {
        setupUi(this);
    
        thread = new QThread();
        thread->start();
        myclass = new MyClass(thread);
        myclass->moveToThread(thread);
        QMetaObject::invokeMethod(myclass,"method",Qt::QueuedConnection);
    
    }
    
    MyClass::MyClass(QThread *thread) {
    
        object = new Object();
        object->moveToThread(thread);
    }
    
    void MyClass::method() {
    //mache was mit object
    }
    


  • Schmeiß doch MyClass (ist doch die alte von QThread abgeleitet Klasse, oder?) komplett über Bord. Du hast die ja nur erstellt, um von QThread abzuleiten.
    Pack alles was du brauchst in Object.
    Ansonsten ist das Problem eh nicht wirklich vorhanden. Der Member "object" ist nicht öffentlich, es wird nur genutzt in Methoden von MyClass (wenn ich dich richtig verstehe). Sobald du eine Methode von MyClass in einem anderen Thread laufen lässt, geschehen die dort getätigten Aufrufe auch im neuen Thread!
    moveToThread brauchst du nur, wenn du die eventloop tauschen willst. Wenn object sich mit SIGNALS/SLOTS mit dem Elternobjekt unterhalten will, und alle object-SLOTS auch im neuen Thread ausgeführt werden sollen, musst du object auch verschieben, ansonsten ist es wurscht.



  • Die Klasse MyClass ist schon notwendig, da die Klasse Object nicht von mir geschrieben wurde, und ich mit der Klasse das object verwalte. So wie ich es oben gepostet habe funktioniert es ja jetzt. Ich weiß nur nciht, ob es einen eleganteren Weg gibt.



  • Achja und das object soll eben die EventLoop vom neuen Thread nutzen. Deswegen das movetothread.


Anmelden zum Antworten