Zoeken…


Opmerkingen

Een paar opmerkingen die hier en hier al zijn vermeld in de officiële documenten:

  • Als een object een bovenliggend item heeft, moet het zich in dezelfde thread bevinden als het bovenliggende item, dat wil zeggen dat het niet naar een nieuwe thread kan worden verplaatst. U kunt ook geen bovenliggend object instellen als het bovenliggende object en het object in verschillende threads wonen
  • Wanneer een object naar een nieuwe thread wordt verplaatst, worden alle onderliggende items ook naar de nieuwe thread verplaatst
  • U kunt alleen objecten naar een nieuwe thread pushen . Je kunt ze niet trekken om een nieuwe thread, dwz u kunt alleen bellen moveToThread van de draad waar het object momenteel in leeft

Basisgebruik van QThread

QThread is een handvat voor een platformthread. Hiermee kunt u de thread beheren door de levensduur ervan te controleren en te vragen dat hij zijn werk afrondt.

In de meeste gevallen wordt inherent aan de klasse niet aanbevolen. De standaard run start een gebeurtenislus die gebeurtenissen kan verzenden naar objecten die in de klasse wonen. Cross-thread signaal- QMetaCallEvent worden geïmplementeerd door een QMetaCallEvent naar het doelobject te verzenden.

Een QObject instantie kan worden verplaatst naar een thread, waar de gebeurtenissen worden QObject , zoals timergebeurtenissen of slot / methode-aanroepen.

Als u aan een thread wilt werken, maakt u eerst uw eigen QObject die is afgeleid van QObject . Verplaats het dan naar de draad. Het object kan automatisch zijn eigen code uitvoeren, bijvoorbeeld door 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);
    }
};

Als uw werknemer kortstondig moet zijn en alleen bestaat terwijl het werk wordt gedaan, kunt u het beste een functor of een threadveilige methode voor uitvoering in de QtConcurrent::run via QtConcurrent::run .

QtConcurrent Run

Als u het beheren van QThreads en primitieven op laag niveau zoals mutexen of semaforen te complex vindt, is Qt Concurrent namespace wat u zoekt. Het bevat klassen die meer threadbeheer op hoog niveau mogelijk maken.

Laten we eens kijken naar Concurrent Run. QtConcurrent::run() kan de functie in een nieuwe thread worden uitgevoerd. Wanneer wil je het gebruiken? Als je een lange operatie hebt en je wilt niet handmatig een thread maken.

Nu de 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();
}

Dus het is eenvoudig: als we een andere functie in een andere thread moeten uitvoeren, roept u QtConcurrent::run , pass-functie en de bijbehorende parameters aan en dat is alles!

QFuture presenteert het resultaat van onze asynchrone berekening. In het geval van QtConcurrent::run we de uitvoering van de functie niet annuleren.

Oproepen van slots uit andere threads

Wanneer een Qt-gebeurtenislus wordt gebruikt om bewerkingen uit te voeren en een niet-Qt-saavy gebruiker moet interageren met die gebeurtenislus, kan het schrijven van de sleuf om reguliere invocaties van een andere thread af te handelen, dingen voor andere gebruikers vereenvoudigen.

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow