Qt
Threading und Parallelität
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