Gleichzeitiger Lauf

Die Funktion QtConcurrent::run() führt eine Funktion in einem separaten Thread aus. Der Rückgabewert der Funktion wird über die QFuture API zur Verfügung gestellt.

QtConcurrent::run() ist eine überladene Methode. Sie können sich diese Überladungen als leicht unterschiedliche Modi vorstellen. Im Basismodus kann die an QtConcurrent::run() übergebene Funktion lediglich ein einziges Berechnungsergebnis an ihren Aufrufer melden. Im Modus "run with promise" kann die an QtConcurrent::run() übergebene Funktion die zusätzliche API QPromise nutzen, die es ermöglicht, mehrere Ergebnisse zu melden, den Fortschritt zu melden, die Berechnung auf Wunsch des Aufrufers anzuhalten oder die Berechnung auf Wunsch des Aufrufers zu beenden.

Diese Funktion ist ein Teil des Qt Concurrent Frameworks.

Gleichzeitiger Lauf (Basismodus)

Die an QtConcurrent::run() übergebene Funktion kann das Ergebnis durch ihren Rückgabewert mitteilen.

Ausführen einer Funktion in einem separaten Thread

Um eine Funktion in einem anderen Thread auszuführen, verwenden Sie QtConcurrent::run():

extern void aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);

Dadurch wird aFunction in einem separaten Thread ausgeführt, der aus dem Standard-Thread QThreadPool stammt. Sie können die Klassen QFuture und QFutureWatcher verwenden, um den Status der Funktion zu überwachen.

Um einen eigenen Thread-Pool zu verwenden, können Sie QThreadPool als erstes Argument übergeben:

extern void aFunction();
QThreadPool pool;
QFuture<void> future = QtConcurrent::run(&pool, aFunction);

Übergabe von Argumenten an die Funktion

Die Übergabe von Argumenten an die Funktion erfolgt, indem man sie dem QtConcurrent::run()-Aufruf direkt nach dem Funktionsnamen hinzufügt. Zum Beispiel:

extern void aFunctionWithArguments(int arg1, double arg2, const QString &string);

int integer = ...;
double floatingPoint = ...;
QString string = ...;

QFuture<void> future = QtConcurrent::run(aFunctionWithArguments, integer, floatingPoint, string);

Eine Kopie jedes Arguments wird an dem Punkt erstellt, an dem QtConcurrent::run() aufgerufen wird, und diese Werte werden an den Thread übergeben, wenn dieser mit der Ausführung der Funktion beginnt. Änderungen an den Argumenten, die nach dem Aufruf von QtConcurrent::run() vorgenommen werden, sind für den Thread nicht sichtbar.

Beachten Sie, dass QtConcurrent::run den direkten Aufruf von überladenen Funktionen nicht unterstützt. Zum Beispiel wird der folgende Code nicht kompiliert:

void foo(int arg);
void foo(int arg1, int arg2);
...
QFuture<void> future = QtConcurrent::run(foo, 42);

Die einfachste Abhilfe ist der Aufruf der überladenen Funktion durch Lambda:

QFuture<void> future = QtConcurrent::run([] { foo(42); });

Oder Sie können dem Compiler mitteilen, welche Überladung er wählen soll, indem Sie ein static_cast verwenden:

QFuture<void> future = QtConcurrent::run(static_cast<void(*)(int)>(foo), 42);

Oder qOverload:

QFuture<void> future = QtConcurrent::run(qOverload<int>(foo), 42);

Rückgabe von Werten aus der Funktion

Jeder Rückgabewert der Funktion ist über QFuture verfügbar:

extern QString functionReturningAString();
QFuture<QString> future = QtConcurrent::run(functionReturningAString);
...
QString result = future.result();

Wenn Sie das Ergebnis nicht benötigen (z. B. weil die Funktion void zurückgibt), ist es effizienter, die Überladung QThreadPool::start() zu verwenden, die ein Funktionsobjekt übernimmt.

Wie oben dokumentiert, wird die Übergabe von Argumenten wie folgt durchgeführt:

extern QString someFunction(const QByteArray &input);

QByteArray bytearray = ...;

QFuture<QString> future = QtConcurrent::run(someFunction, bytearray);
...
QString result = future.result();

Beachten Sie, dass die Funktion QFuture::result() blockiert und darauf wartet, dass das Ergebnis verfügbar wird. Verwenden Sie QFutureWatcher, um eine Benachrichtigung zu erhalten, wenn die Funktion ausgeführt wurde und das Ergebnis verfügbar ist.

Zusätzliche API-Funktionen

Verwendung von Mitgliedsfunktionen

QtConcurrent::run() akzeptiert auch Zeiger auf Mitgliedsfunktionen. Das erste Argument muss entweder eine const-Referenz oder ein Zeiger auf eine Instanz der Klasse sein. Die Übergabe als const-Referenz ist nützlich, wenn man const-Member-Funktionen aufruft; die Übergabe als Pointer ist nützlich, wenn man non-const-Member-Funktionen aufruft, die die Instanz verändern.

Ein Beispiel: Der Aufruf von QByteArray::split() (eine const-Mitgliedsfunktion) in einem separaten Thread wird wie folgt durchgeführt:

// call 'QList<QByteArray>  QByteArray::split(char sep) const' in a separate thread
QByteArray bytearray = "hello world";
QFuture<QList<QByteArray> > future = QtConcurrent::run(&QByteArray::split, bytearray, ' ');
...
QList<QByteArray> result = future.result();

Der Aufruf einer Non-Const-Mitgliedsfunktion erfolgt so:

// call 'void QImage::invertPixels(InvertMode mode)' in a separate thread
QImage image = ...;
QFuture<void> future = QtConcurrent::run(&QImage::invertPixels, &image, QImage::InvertRgba);
...
future.waitForFinished();
// At this point, the pixels in 'image' have been inverted

Verwendung von Lambda-Funktionen

Der Aufruf einer Lambda-Funktion wird wie folgt durchgeführt:

QFuture<void> future = QtConcurrent::run([=]() {
    // Code in this block will run in another thread
});
...

Der Aufruf einer Funktion ändert ein Objekt, das als Referenz übergeben wurde, wie folgt:

static void addOne(int &n) { ++n; }
...
int n = 42;
QtConcurrent::run(&addOne, std::ref(n)).waitForFinished(); // n == 43

Die Verwendung eines aufrufbaren Objekts erfolgt wie folgt:

struct TestClass
{
    void operator()(int s1) { s = s1; }
    int s = 42;
};

...

TestClass o;

// Modify original object
QtConcurrent::run(std::ref(o), 15).waitForFinished(); // o.s == 15

// Modify a copy of the original object
QtConcurrent::run(o, 42).waitForFinished(); // o.s == 15

// Use a temporary object
QtConcurrent::run(TestClass(), 42).waitForFinished();

// Ill-formed
QtConcurrent::run(&o, 42).waitForFinished(); // compilation error

Gleichzeitiger Lauf mit Versprechen

Der Modus Run With Promise ermöglicht mehr Kontrolle über die laufende Aufgabe im Vergleich zum Grundmodus von QtConcurrent::run(). Er erlaubt es, den Fortschritt der laufenden Aufgabe zu melden, mehrere Ergebnisse zu melden, die Ausführung zu unterbrechen, wenn dies gewünscht wurde, oder die Aufgabe auf Wunsch des Aufrufers abzubrechen.

Das obligatorische Argument QPromise

Die Funktion, die an QtConcurrent::run() im Modus Run With Promise übergeben wird, muss ein zusätzliches Argument vom Typ QPromise<T> & haben, wobei T der Typ des Berechnungsergebnisses ist (er sollte mit dem Typ T von QFuture<T> übereinstimmen, der von QtConcurrent::run() zurückgegeben wird), wie z.B:

extern void aFunction(QPromise<void> &promise);
QFuture<void> future = QtConcurrent::run(aFunction);

Das Argument promise wird innerhalb der Funktion QtConcurrent::run() instanziiert, und seine Referenz wird an die aufgerufene Funktion aFunction übergeben, so dass der Benutzer es weder instanziieren noch explizit übergeben muss, wenn er QtConcurrent::run() in diesem Modus aufruft.

Das zusätzliche Argument vom Typ QPromise muss immer als erstes Argument in der Argumentenliste der Funktion erscheinen, wie z.B.:

extern void aFunction(QPromise<void> &promise, int arg1, const QString &arg2);

int integer = ...;
QString string = ...;

QFuture<void> future = QtConcurrent::run(aFunction, integer, string);

Ergebnisse melden

Im Gegensatz zum Basismodus von QtConcurrent::run() wird erwartet, dass die an QtConcurrent::run() übergebene Funktion im Modus Run With Promise immer den Typ void zurückgibt. Die Ergebnismeldung erfolgt über das zusätzliche Argument vom Typ QPromise. Es ermöglicht auch mehrere Ergebnisberichte, wie z.B.:

void helloWorldFunction(QPromise<QString> &promise)
{
    promise.addResult("Hello");
    promise.addResult("world");
}

QFuture<QString> future = QtConcurrent::run(helloWorldFunction);
...
QList<QString> results = future.results();

Hinweis: Es besteht keine Notwendigkeit, QPromise::start() und QPromise::finish() aufzurufen, um den Beginn und das Ende der Berechnung anzuzeigen (wie Sie es normalerweise tun würden, wenn Sie QPromise verwenden). QtConcurrent::run() wird sie immer vor dem Start und nach dem Ende der Ausführung aufrufen.

Unterbrechung und Abbruch der Ausführung

Die QPromise API ermöglicht auch das Unterbrechen und Abbrechen der Berechnung, wenn dies gewünscht wird:

void aFunction(QPromise<int> &promise)
{
    for (int i = 0; i < 100; ++i) {
        promise.suspendIfRequested();
        if (promise.isCanceled())
            return;

        // computes the next result, may be time consuming like 1 second
        const int res = ... ;
        promise.addResult(res);
    }
}

QFuture<int> future = QtConcurrent::run(aFunction);

... // user pressed a pause button after 10 seconds
future.suspend();

... // user pressed a resume button after 10 seconds
future.resume();

... // user pressed a cancel button after 10 seconds
future.cancel();

Der Aufruf von future.suspend() fordert die laufende Aufgabe auf, ihre Ausführung anzuhalten. Nach dem Aufruf dieser Methode wird die laufende Aufgabe nach dem nächsten Aufruf von promise.suspendIfRequested() in ihrer Iterationsschleife angehalten. In diesem Fall blockiert die laufende Task bei einem Aufruf von promise.suspendIfRequested(). Der blockierte Aufruf wird nach dem Aufruf von future.resume() freigegeben. Beachten Sie, dass suspendIfRequested() intern eine Wartebedingung verwendet, um die Blockierung aufzuheben, so dass der laufende Thread in einen Leerlaufzustand übergeht, anstatt seine Ressourcen zu verschwenden, wenn er blockiert ist, um regelmäßig zu prüfen, ob die Wiederaufnahmeanforderung vom Thread des Aufrufers kam.

Der Aufruf von future.cancel() in der letzten Zeile bewirkt, dass der nächste Aufruf von promise.isCanceled() true zurückgibt und aFunction sofort ohne weitere Ergebnismeldung zurückkehrt.

Hinweis: Es besteht keine Notwendigkeit, QPromise::finish() aufzurufen, um die Berechnung nach dem Abbruch zu stoppen (wie Sie es normalerweise tun würden, wenn Sie QPromise verwenden). QtConcurrent::run() wird es immer nach Beendigung der Ausführung aufrufen.

Fortschrittsbericht

Es ist auch möglich, den Fortschritt einer Aufgabe unabhängig von der Ergebnismeldung zu melden, wie z.B:

void aFunction(QPromise<int> &promise) { promise.setProgressRange(0, 100); int result = 0; for(int i = 0; i < 100;++i) { // berechnet einen Teil der Aufgabe const int part = ...; result += part; promise.setProgressValue(i); } promise.addResult(result); }QFutureWatcher<int> watcher;QObject::connect(&watcher, &QFutureWatcher::progressValueChanged, [](int progress){ ...; // GUI mit einem Fortschritt aktualisieren    qDebug() << "current progress:" << progress;
}); watcher.setFuture(QtConcurrent::run(aFunction));

Der Aufrufer installiert die QFutureWatcher für das von QtConcurrent::run() zurückgegebene QFuture, um eine Verbindung zu dessen progressValueChanged() Signal herzustellen und z.B. die grafische Benutzeroberfläche entsprechend zu aktualisieren.

Aufrufen von Funktionen mit überladenen operator()()

Standardmäßig unterstützt QtConcurrent::run() keine Funktoren mit überladenem operator()() im Run With Promise Modus. Im Falle von überladenen Funktoren muss der Benutzer den Ergebnistyp explizit als Template-Parameter angeben, der an QtConcurrent::run() übergeben wird, z.B:

struct Functor {
    void operator()(QPromise<int> &) { }
    void operator()(QPromise<double> &) { }
};

Functor f;
run<double>(f); // this will select the 2nd overload
// run(f);      // error, both candidate overloads potentially match

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.