Sök…


Anmärkningar

Några anteckningar som redan nämns i de officiella dokumenten här och här :

  • Om ett objekt har en förälder måste det vara i samma tråd som föräldern, dvs. det kan inte flyttas till en ny tråd, och du kan inte heller ställa in en förälder till ett objekt om föräldern och objektet lever i olika trådar
  • När ett objekt flyttas till en ny tråd flyttas alla dess barn till den nya tråden
  • Du kan bara skjuta objekt till en ny tråd. Du kan inte dra dem till en ny tråd, dvs. du kan bara ringa moveToThread från tråden där objektet för närvarande bor i

Grundläggande användning av QThread

QThread är ett handtag till en plattformstråd. Det låter dig hantera tråden genom att övervaka dess livslängd och begära att den är färdig med sitt arbete.

I de flesta fall rekommenderas inte arv från klassen. Standard run metoden startar en slinga som kan skicka händelser till objekt som bor i klassen. Tvärgängade signalspåranslutningar implementeras genom att skicka ett QMetaCallEvent till QMetaCallEvent .

En QObject instans kan flyttas till en tråd, där den kommer att behandla händelserna, t.ex. timerhändelser eller slot / metodsamtal.

Om du vill arbeta på en tråd ska du först skapa din egen arbetarklass som härrör från QObject . Flytta sedan den till tråden. Objektet kan köra sin egen kod automatiskt, t.ex. med hjälp av 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);
    }
};

Om din arbetare ska vara flyktig och bara existera medan arbetet utförs, är det bäst att skicka in en funktor eller en gängsäker metod för körning i QtConcurrent::run via QtConcurrent::run .

QtConcurrent Run

Om du tycker att hantera QThreads och lågnivå-primitiv som mutexer eller semaforer för komplicerade, är Qt Concurrent namnutrymme det du letar efter. Den innehåller klasser som möjliggör mer trådhantering på hög nivå.

Låt oss titta på Samtidig körning. QtConcurrent::run() gör det möjligt att köra funktionen i en ny tråd. När vill du använda det? När du har lite lång drift och inte vill skapa tråd manuellt.

Nu koden:

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

Så saker är enkla: när vi behöver köra en annan funktion i en annan tråd, ring bara QtConcurrent::run , pass-funktion och dess parametrar och det är det!

QFuture presenterar resultatet av vår asynkrona beräkning. Vid QtConcurrent::run vi inte avbryta funktionen exekvering.

Åkalla spår från andra trådar

När en Qt-händelsslinga används för att utföra operationer och en användare som inte är Qt-saavy måste interagera med den händelsslingan, kan skrivning av kortplatsen för att hantera regelbundna invokationer från en annan tråd förenkla saker för andra användare.

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow