Suche…


Bemerkungen

Einige Anmerkungen, die bereits hier und hier in den offiziellen Dokumenten erwähnt werden :

  • Wenn ein Objekt über ein übergeordnetes Objekt verfügt, muss es sich in demselben Thread befinden wie das übergeordnete Element, dh es kann nicht in einen neuen Thread verschoben werden. Außerdem können Sie einem übergeordneten Objekt kein Objekt zuweisen, wenn das übergeordnete Element und das Objekt in unterschiedlichen Threads leben
  • Wenn ein Objekt in einen neuen Thread verschoben wird, werden auch alle untergeordneten Objekte in den neuen Thread verschoben
  • Sie können nur Objekte in einen neuen Thread drücken. Sie können sie zu einem neuen Thread nicht ziehen, dh Sie können nur nennen moveToThread aus dem Thread , in dem das Objekt lebt derzeit in

Grundlegende Verwendung von QThread

QThread ist ein Handle für einen Plattform-Thread. Sie können den Thread verwalten, indem Sie seine Lebensdauer überwachen und anfordern, dass die Arbeit abgeschlossen ist.

In den meisten Fällen wird das Erben der Klasse nicht empfohlen. Der run Methode startet eine Ereignisschleife , die in der Klasse lebenden Veranstaltungen Objekte versenden können. Cross-Thread-Signalschlitzverbindungen werden implementiert, indem ein QMetaCallEvent an das Zielobjekt QMetaCallEvent wird.

Eine QObject Instanz kann in einen Thread verschoben werden, wo sie ihre Ereignisse verarbeitet, z. B. Timer-Ereignisse oder Slot- / Methodenaufrufe.

Um an einem Thread zu arbeiten, erstellen Sie zuerst Ihre eigene Arbeiterklasse, die von QObject . Dann verschieben Sie es auf den Thread. Das Objekt kann seinen eigenen Code automatisch ausführen, z. B. mit QMetaObject::invokeMethod() .

#include <QObject>

class MyWorker : public QObject
{
    Q_OBJECT
public:
    Q_SLOT void doWork() {
        qDebug() << "doWork()" << QThread::currentThread();
        // and do some long operation here
    }
    MyWorker(QObject * parent = nullptr) : QObject{parent} {}
};

class MyController : public QObject
{
    Q_OBJECT
    Worker worker;
    QThread workerThread;
public:
    MyController()  {
        worker.moveToThread(&workerThread);
        // provide meaningful debug output
        workerThread.setObjectName("workerThread");
        workerThread.start();
        // the thread starts the event loop and blocks waiting for events
    }
    ~MyController()  {
        workerThread.quit();
        workerThread.wait();
    }
    void operate() {
        // Qt::QueuedConnection ensures that the slot is invoked in its own thread
        QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);
    }
};

Wenn Ihr Worker flüchtig sein sollte und nur existiert, während seine Arbeit erledigt ist, QtConcurrent::run es sich, einen Functor oder eine Thread-sichere Methode zur Ausführung im Thread-Pool über QtConcurrent::run .

QtConcurrent Run

Wenn Sie die Verwaltung von QThreads und einfachen Primitiven wie Mutexe oder Semaphoren als zu komplex empfinden, ist der Qt Concurrent-Namespace genau das Richtige für Sie. Es enthält Klassen, die eine höhere Thread-Verwaltung ermöglichen.

Schauen wir uns Concurrent Run an. QtConcurrent::run() erlaubt die Ausführung einer Funktion in einem neuen Thread. Wann möchten Sie es verwenden? Wenn Sie einen langen Betrieb haben und den Thread nicht manuell erstellen möchten.

Nun der Code:

#include <qtconcurrentrun.h>

void longOperationFunction(string parameter)
{
    // we are already in another thread
    // long stuff here
} 

void mainThreadFunction()
{
    QFuture<void> f = run(longOperationFunction, "argToPass");
    f.waitForFinished();
}

Die Dinge sind also einfach: Wenn wir eine andere Funktion in einem anderen Thread QtConcurrent::run , rufen QtConcurrent::run einfach QtConcurrent::run , übergeben Sie die Funktion und ihre Parameter und QtConcurrent::run !

QFuture präsentiert das Ergebnis unserer asynchronen Berechnung. Im Falle von QtConcurrent::run wir die Funktionsausführung nicht abbrechen.

Slots von anderen Threads aufrufen

Wenn eine Qt-Ereignisschleife zum Ausführen von Vorgängen verwendet wird und ein Benutzer, der kein Qt-saavy-Benutzer ist, mit dieser Ereignisschleife interagieren muss, kann das Schreiben des Slot für reguläre Aufrufe aus einem anderen Thread die Arbeit für andere Benutzer vereinfachen.

main.cpp:

#include "OperationExecutioner.h"
#include <QCoreApplication>
#include <QThread>

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    QThread thrd;
    thrd.setObjectName("thrd");
    thrd.start();
    while(!thrd.isRunning())
        QThread::msleep(10);

    OperationExecutioner* oe = new OperationExecutioner;
    oe->moveToThread(&thrd);
    oe->doIt1(123,'A');
    oe->deleteLater();
    thrd.quit();
    while(!thrd.isFinished())
        QThread::msleep(10);

    return 0;
}

OperationExecutioner.h:

#ifndef OPERATION_EXECUTIONER_H
#define OPERATION_EXECUTIONER_H

#include <QObject>

class OperationExecutioner : public QObject
{
    Q_OBJECT
public slots:
    void doIt1(int argi, char argc);
};

#endif  // OPERATION_EXECUTIONER_H

OperationExecutioner.cpp:

#include "OperationExecutioner.h"
#include <QMetaObject>
#include <QThread>
#include <QDebug>

void OperationExecutioner::doIt1(int argi, char argc)
{
    if (QThread::currentThread() != thread()) {
        qInfo() << "Called from thread" << QThread::currentThread();
        QMetaObject::invokeMethod(this, "doIt1", Qt::QueuedConnection,
                                  Q_ARG(int,argi), Q_ARG(char,argc));
        return;
    }

    qInfo() << "Called from thread" << QThread::currentThread()
            << "with args" << argi << argc;
}

OperationExecutioner.pro:

HEADERS += OperationExecutioner.h
SOURCES += main.cpp OperationExecutioner.cpp
QT -= gui


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow