Recherche…


Remarques

Quelques notes déjà mentionnées dans les docs officiels ici et ici :

  • Si un objet a un parent, il doit être dans le même thread que le parent, c.-à-d. Qu'il ne peut pas être déplacé vers un nouveau thread, et que vous ne pouvez pas définir un parent sur un objet si le parent et l'objet vivent dans des threads différents
  • Lorsqu'un objet est déplacé vers un nouveau thread, tous ses enfants sont également déplacés vers le nouveau thread
  • Vous ne pouvez que pousser des objets vers un nouveau thread. Vous ne pouvez pas les tirer vers un nouveau thread, c’est-à-dire que vous ne pouvez appeler que moveToThread partir du thread où l’objet vit actuellement

Utilisation basique de QThread

QThread est un handle vers un thread de plate-forme. Il vous permet de gérer le thread en surveillant sa durée de vie et en lui demandant de terminer son travail.

Dans la plupart des cas, l'héritage de la classe n'est pas recommandé. La méthode d' run par défaut lance une boucle d'événements pouvant envoyer des événements aux objets de la classe. Les connexions d'intervalle de signal entre threads sont implémentées en envoyant un QMetaCallEvent à l'objet cible.

Une instance de QObject peut être déplacée vers un thread, où elle traitera ses événements, tels que les événements du minuteur ou les appels d'emplacement / méthode.

Pour travailler sur un thread, commencez par créer votre propre classe de travail QObject de QObject . Puis déplacez-le sur le fil. L'objet peut exécuter son propre code automatiquement, par exemple en utilisant 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);
    }
};

Si votre agent doit être éphémère et n'existe que pendant son travail, il est préférable de soumettre un foncteur ou une méthode thread-safe pour exécution dans le pool de threads via QtConcurrent::run .

QtConcurrent Run

Si vous trouvez que la gestion de QThreads et de primitives de bas niveau telles que les mutex ou les sémaphores est trop complexe, Qt Concurrent est ce que vous recherchez. Il comprend des classes qui permettent une gestion plus poussée des threads.

Regardons Exécution simultanée. QtConcurrent::run() permet d'exécuter une fonction dans un nouveau thread. Quand aimeriez-vous l'utiliser? Lorsque vous avez une longue opération et que vous ne voulez pas créer de thread manuellement.

Maintenant le 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();
}

Les choses sont donc simples: lorsque nous devons exécuter une autre fonction dans un autre thread, appelez simplement QtConcurrent::run , pass function et ses paramètres et voilà!

QFuture présente le résultat de notre calcul asynchrone. Dans le cas de QtConcurrent::run nous ne pouvons pas annuler l'exécution de la fonction.

Invocation de slots à partir d'autres threads

Lorsqu'une boucle d'événement Qt est utilisée pour effectuer des opérations et qu'un utilisateur non-Qt-saavy doit interagir avec cette boucle d'événement, l'écriture de l'emplacement pour gérer des appels réguliers à partir d'un autre thread peut simplifier les choses pour les autres utilisateurs.

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow