Sur cette page

Exécution concurrente

La fonction QtConcurrent::run() exécute une fonction dans un thread distinct. La valeur de retour de la fonction est accessible via l'API « QFuture ».

QtConcurrent::run() est une méthode surchargée. Ces surcharges peuvent être considérées comme des modes légèrement différents. En mode de base, la fonction transmise à QtConcurrent::run() ne peut renvoyer qu’un seul résultat de calcul à son appelant. En mode « exécution avec promesse », la fonction transmise à QtConcurrent::run() peut utiliser l’API QPromise, qui permet de renvoyer plusieurs résultats, de signaler la progression, de suspendre le calcul à la demande de l’appelant ou d’arrêter le calcul à la demande de ce dernier.

Cette fonction fait partie du framework « Qt Concurrent ».

Optimisation des inclusions

Si vous incluez l'en-tête <QtConcurrent>, l'intégralité du module Qt Concurrent ainsi que l'intégralité du module Qt Core seront incluses, ce qui peut augmenter les temps de compilation et la taille des binaires. Pour utiliser la fonction QtConcurrent::run(), vous pouvez inclure un en-tête plus spécifique :

#include <QtConcurrentRun>

Exécution concurrente (mode de base)

La fonction transmise à QtConcurrent::run() peut renvoyer le résultat via sa valeur de retour.

Exécution d'une fonction dans un thread distinct

Pour exécuter une fonction dans un autre thread, utilisez QtConcurrent::run() :

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

Cela exécutera aFunction dans un thread distinct obtenu à partir de l'QThreadPool par défaut. Vous pouvez utiliser les classes QFuture et QFutureWatcher pour surveiller l'état de la fonction.

Pour utiliser un pool de threads dédié, vous pouvez passer la fonction QThreadPool en premier argument :

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

Passage d’arguments à la fonction

Pour passer des arguments à la fonction, il suffit de les ajouter à l'appel QtConcurrent::run() immédiatement après le nom de la fonction. Par exemple :

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);

Une copie de chaque argument est créée au moment où QtConcurrent::run() est appelé, et ces valeurs sont transmises au thread lorsque celui-ci commence à exécuter la fonction. Les modifications apportées aux arguments après l’appel de QtConcurrent::run() ne sont pas visibles par le thread.

Notez qu’ QtConcurrent::run ne prend pas en charge l’appel direct de fonctions surchargées. Par exemple, le code ci-dessous ne se compilera pas :

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

La solution la plus simple consiste à appeler la fonction surchargée via un lambda :

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

Vous pouvez également indiquer au compilateur quelle surcharge choisir en utilisant une static_cast:

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

Ou « qOverload » :

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

Retour de valeurs depuis la fonction

Toute valeur renvoyée par la fonction est accessible via ` QFuture` :

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

Si vous n'avez pas besoin du résultat (par exemple, parce que la fonction renvoie void), il est plus efficace d'utiliser la surcharge QThreadPool::start() qui prend un objet fonction.

Comme indiqué ci-dessus, le passage des arguments s'effectue ainsi :

extern QString someFunction(const QByteArray &input);

QByteArray bytearray = ...;

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

Notez que la fonction ` QFuture::result()` bloque et attend que le résultat soit disponible. Utilisez ` QFutureWatcher ` pour être averti lorsque la fonction a terminé son exécution et que le résultat est disponible.

Fonctionnalités supplémentaires de l'API

Utilisation des fonctions membres

La fonction QtConcurrent::run() accepte également des pointeurs vers des fonctions membres. Dans Qt 6, le premier argument doit être le pointeur vers la fonction membre, suivi soit d'une référence const, soit d'un pointeur vers une instance de la classe. Le passage d'une référence const est utile pour appeler des fonctions membres const ; le passage d'un pointeur est utile pour appeler des fonctions membres non const qui modifient l'instance.

Par exemple, pour appeler ` QByteArray::split()` (une fonction membre `const`) dans un thread distinct, on procède comme suit :

// 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();

L'appel d'une fonction membre non const s'effectue comme suit :

// 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

Utilisation des fonctions lambda

L'appel d'une fonction lambda s'effectue comme suit :

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

Pour appeler une fonction qui modifie un objet passé par référence, procédez comme suit :

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

L'utilisation d'un objet appelable se fait comme suit :

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

Exécution concurrente avec Promise

Le mode « Run With Promise » offre un contrôle accru sur la tâche en cours d'exécution par rapport au mode de base de QtConcurrent::run(). Il permet de suivre la progression de la tâche en cours, de renvoyer plusieurs résultats, de suspendre l'exécution si cela est demandé, ou d'annuler la tâche à la demande de l'appelant.

L'argument obligatoire QPromise

La fonction transmise à QtConcurrent::run() en mode « Run With Promise » doit comporter un argument supplémentaire de type « QPromise<T> & », où « T » est le type du résultat du calcul (il doit correspondre au type « T » de l’objet « QFuture<T>» renvoyé par QtConcurrent::run()), comme par exemple :

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

L’argument promise est instancié à l’intérieur de la fonction QtConcurrent::run(), et sa référence est transmise à la fonction aFunction invoquée ; l’utilisateur n’a donc pas besoin de l’instancier, ni de le passer explicitement lors de l’appel de QtConcurrent::run() dans ce mode.

L'argument supplémentaire de type ` QPromise ` doit toujours figurer en premier dans la liste des arguments de la fonction, comme suit :

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

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

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

Rapport des résultats

Contrairement au mode de base de QtConcurrent::run(), la fonction transmise à QtConcurrent::run() en mode « Run With Promise » doit toujours renvoyer le type `void`. La communication des résultats s'effectue via l'argument supplémentaire de type ` QPromise `. Cela permet également de communiquer plusieurs résultats, comme ceci :

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

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

Remarque : il n'est pas nécessaire d'appeler ` QPromise::start()` et ` QPromise::finish()` pour indiquer le début et la fin du calcul (comme vous le feriez normalement en utilisant ` QPromise`). `QtConcurrent::run()` les appellera toujours avant de démarrer et après avoir terminé l'exécution.

Suspension et annulation de l’exécution

L’API QPromise permet également de suspendre et d’annuler le calcul, si nécessaire :

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();

L'appel à ` future.suspend() ` demande à la tâche en cours d’exécution de mettre son exécution en attente. Après l’appel de cette méthode, la tâche en cours d’exécution se suspendra après le prochain appel à ` promise.suspendIfRequested() ` dans sa boucle d’itération. Dans ce cas, la tâche en cours d’exécution se bloquera lors d’un appel à ` promise.suspendIfRequested()`. L’appel bloqué se débloquera après l’appel à ` future.resume() `. Notez qu’en interne, suspendIfRequested() utilise une condition d’attente pour se débloquer ; ainsi, le thread en cours d’exécution passe en état d’inactivité au lieu de gaspiller ses ressources lorsqu’il est bloqué, afin de vérifier périodiquement si la demande de reprise provient du thread de l’appelant.

L’appel à ` future.cancel() ` dans la dernière ligne fait en sorte que le prochain appel à ` promise.isCanceled() ` renvoie ` true ` et que ` aFunction ` se termine immédiatement sans générer d’autre rapport de résultat.

Remarque : il n'est pas nécessaire d'appeler QPromise::finish() pour arrêter le calcul après l'annulation (comme vous le feriez normalement en utilisant QPromise). QtConcurrent::run() l'appellera toujours après avoir terminé l'exécution.

Suivi de la progression

Il est également possible de signaler la progression d'une tâche indépendamment du rapport de résultat, comme suit :

void aFunction(QPromise<int> &promise)
{
    promise.setProgressRange(0, 100);
    int result = 0;
    for (int i = 0; i < 100;++i) {
       // calcule une partie de la tâche
        const int part =...;
        result+= part;
        promise.setProgressValue(i);
    }
    promise.addResult(result);
}

QFutureWatcher<int> watcher;
QObject::connect(&watcher, &QFutureWatcher::progressValueChanged, [](int progress){
    ...; // met à jour l’interface graphique avec la progression
    qDebug() << "current progress:" << progress;
});
watcher.setFuture(QtConcurrent::run(aFunction));

L'appelant installe l'QFutureWatcher pour l'QFuture renvoyé par QtConcurrent::run() afin de se connecter à son signal progressValueChanged() et de mettre à jour, par exemple, l'interface utilisateur graphique en conséquence.

Appel de fonctions avec l'opérateur () surchargé

Par défaut, QtConcurrent::run() ne prend pas en charge les foncteurs avec un opérateur () surchargé en mode « Run With Promise ». Dans le cas de foncteurs surchargés, l’utilisateur doit spécifier explicitement le type de résultat en tant que paramètre de modèle passé à QtConcurrent::run(), comme suit :

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

© 2026 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.