QThread richtig einsetzen



  • Argh, my fault... das kommt davon wenn man nicht aufpasst und Google noch schnell QT 4.x Dokus raus haut.



  • Hi,

    ich muss noch mal fragen "Sorry"
    So sieht es aus die Connect Funktionen in der Konstruktor:

    connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &QThread::deleteLater);
    	connect(m_pvAgilentWorker, &CAgilentLan::finished, m_pvAgilentWorker, &CAgilentLan::deleteLater);
    

    die

    m_pvWorkerThread->start();
    

    Wo soll ich die bitte aufrufen?
    Wenn ich die in der Konstruktor aufrufe dann knallt. Wenn ich die auch gar nicht aufrufe dann knallt auch aber in eine andere Stelle "Wo das Programm beendet wird".



  • Du musst das an der Stelle aufrufen, an der du möchtest, dass der Thread anfängt seine Aufgaben abzuarbeiten.

    Was für einen Fehler bekommst du denn, wenn du das im Konstruktor aufrufst? Eigentlich sollte das egal sein.
    Und wo stürzt er dann genau ab? Sicher nicht bei

    m_pvWorkerThread->start();
    

    , oder?



  • Schlangenmensch schrieb:

    Du musst das an der Stelle aufrufen, an der du möchtest, dass der Thread anfängt seine Aufgaben abzuarbeiten.

    Was für einen Fehler bekommst du denn, wenn du das im Konstruktor aufrufst? Eigentlich sollte das egal sein.
    Und wo stürzt er dann genau ab? Sicher nicht bei

    m_pvWorkerThread->start();
    

    , oder?

    An diese Stelle nicht.

    m_pvWorkerThread->start()
    

    aber bei Erzeugung das Object wo die CAgilent aufgerufen wird.
    Fehlermeldung:

    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 4c19f68. Receiver '' (of type 'QNativeSocketEngine') was created in thread 4c582e0", file kernel\qcoreapplication.cpp, line 541
    


  • Das scheint wieder am löschen des Objektes zu liegen.

    Zum einen würde ich dir empfehlen en QThread nicht mit "new" zu erstellen, sondern einfach auf dem Stack.

    Zum anderen, schau dir die Zeile nochmal an:

    connect(m_pvAgilentWorker, &CAgilentLan::finished, m_pvAgilentWorker, &CAgilentLan::deleteLater)
    

    Du willst das Objekt löschen, wenn der Thread fertig ist. Also muss welches Objekt der Sender sein?

    Außerdem, wenn du das häufiger verwenden möchtest (was ja der Ausgangspunkt war), willst du das nicht nach dem finished Signal des Threads löschen, sondern ja eventuell nochmal verwenden.



  • Hallo,
    Ich habe das Connect so angepasst:

    connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &CAgilentLan::deleteLater);
    

    Beim Application Starten bekomme ich eine Fehlermeldung "MyApllication.exe has triggered a breakpoint"in folgende Codeabschnitt:

    static void deallocate(QArrayData *data)
        {
            Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
            QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy));
        }
    

    Egal wie ich das umdrehe habe ich stets die gleiche Fehlermeldung.



  • Was sind denn die letzten Zeilen Code die aufgerufen werden und die du geschrieben hast? Sollte sich aus dem Callstack ablesen lassen.



  • Hi,

    Schlangenmensch schrieb:

    Was sind denn die letzten Zeilen Code die aufgerufen werden und die du geschrieben hast? Sollte sich aus dem Callstack ablesen lassen.

    In der Konstruktur wo das Object

    CAgilentLan
    

    aufgerufen wird folgende Code geschrieben:

    m_pvWorkerThread = new QThread();
    	m_pvAgilentWorker = new CAgilentLan(settings_l.strfuGetIP_DSO(), 500, settings_l.bofuGetSimulate());
    	m_pvAgilentWorker->moveToThread(m_pvWorkerThread);
    	connect(m_pvWorkerThread, &QThread::started, m_pvAgilentWorker, &CAgilentLan::agilentStart);
    	connect(m_pvAgilentWorker, &CAgilentLan::finished, m_pvWorkerThread, &QThread::quit);
    
    	connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &QThread::deleteLater);
    	connect(m_pvWorkerThread, &QThread::finished, m_pvWorkerThread, &CAgilentLan::deleteLater);
    	m_pvWorkerThread->start();
    

    und genau hier liegt der Fehler.



  • Was soll die folgende Zeile machen???

    connect(m_pvAgilentWorker, &CAgilentLan::finished, m_pvWorkerThread, &QThread::quit);
    


  • wenn des Signals der Object CAgilentLan aufgerufen wird. dann muss der Thread zu ende sein.



  • QThread::quit() beendet die Eventloop in deinem Thread, falls vorhanden. QThread::terminate() kann threads wohl beenden. Wann das genau passiert ist wohl System abhängig
    Aber willst du das wirklich? Der Agilenten ist an den Thread gekoppelt und führt die Aktion aus der Klasse aus, ich denke nicht, dass das der Weg ist, wie das funktionieren kann.

    Außerdem glaube ich nicht, dass dein Agilenten Objekt das Signal emited, oder Emittenten sollte.

    Kleiner Tipp: Bau dir erstmal in einer Sandbox ein funktionierendes Beispiel mit einem QThread. Und versuche das dann auf deinen Agilenten zu übertragen.



  • Hallo zusammen,

    @Schlangenmensch

    Problem habe ich mittlerweile gelöst.
    Es reicht eigentlich vollkommen, wenn ich Signal/Slot verwende.
    Danke noch mal.



  • Ich nutze einfach mal den Thread hier weil ich ebenfalls ein Problem mit QThread habe.

    Ich nutze QThread folgendermaßen, um aufwändige Arbeit zu erledigen:

    TimeSeriesManager::TimeSeriesManager( QObject *parent ) :
        QObject( parent )
    {
        auto worker = new TimeSeriesLoader();
        worker->moveToThread( &thread );
    
        assert( QObject::connect( this, SIGNAL( sigLoadTimeSeries(std::shared_ptr<TimeSeries>)), worker, SLOT(onLoadTimeSeries(std::shared_ptr<TimeSeries>)) ) );
        assert( QObject::connect( worker, SIGNAL(sigTimeSeriesLoaded(std::shared_ptr<TimeSeries>)), this, SLOT(onTimeSeriesLoaded(std::shared_ptr<TimeSeries>)) ) );
        assert( QObject::connect( &thread, SIGNAL(finished()), worker, SLOT(deleteLater())));
        thread.start();
    }
    
    TimeSeriesManager::~TimeSeriesManager()
    {
        thread.quit();
        thread.wait();
    }
    

    D.h. der Thread läuft dauernd und bekommt über SIGNAL/SLOT seine Arbeit zugewiesen. Beim Start der Applikation bekommt der Thread so an die 2000 Jobs übertragen.

    Nun will ich die Anwendung beenden. Das Problem ist, dass der Thread trotz Aufruf von "quit()" erst noch seine Eventloop abarbeitet, d.h. die Anwendung endet erst, wenn der Thread alle seine Jobs abgearbeitet hat, was reichlich bescheuert ist.

    Gibt es eine Möglichkeit den Thread zu überzeugen, die Eventloop zu leeren?



  • Laut source nicht.

    Das ist recht spannend...der eventDispatcher scheint selbst einen QAbstractEventDispatcher::interrupt() zu "ignorieren"...

    Dir wird wohl nichts anderes uebrig bleiben als deinen eigenen QAbstractEventDispatcher zu schreiben.

    Edit: Hast du es bereits mit QThread::setTerminationEnabled und QThread::terminate probiert?



  • QThread::terminate gibt aber keine Garantie, wann und wo der Thread beendet wird. Könnte also mitten in einer Schreiboperation passieren, was zu einem inkonsistenten Zustand führen könnte.

    Wenn ich It0101 richtig verstehe, soll der Thread auch ruhig seinen aktuellen Job noch abarbeiten, nur die anderen 99, die noch in der Queue sind, nicht mehr, oder?



  • Schlangenmensch schrieb:

    Wenn ich It0101 richtig verstehe, soll der Thread auch ruhig seinen aktuellen Job noch abarbeiten, nur die anderen 99, die noch in der Queue sind, nicht mehr, oder?

    Genau das.
    Ich könnte auch das "wait" einfach weglassen und den Thread dann sterben lassen, während er noch läuft. Beim ShutDown der Applikation wäre das ja halb so schlimm.

    Aber ich will es halt möglichst ordentlich beenden. Daher das wait(). Leider wartet er mir etwas zu lange 😉



  • Ich finde es auch extrem befremdlich, dass QEventLoop keinerlei interrupt oder aehnliches zur verfuegung stellt...Ich meine, das wird doch vermutlich oefter benoetigt, wenn man unendliche queues laufen hat.



  • Dachte ich eigentlich auch...


Anmelden zum Antworten