QThread vs std :: thread

8

Ich sah verschiedene Themen auf "Pthread vs. std :: thread" und "QThread vs pthread", aber keine auf "std :: thread vs QThread".

Ich muss eine Software programmieren, um einen 3D-Drucker zu steuern und muss Threads verwenden. Es wird einen Thread geben, der die Sicherheit ständig überprüft, ein anderer, um den Druckprozess auszuführen, einige, um jede Hardwarekomponente (Bewegung, Jet, ...) separat zu fahren, etc ... Das Programm wurde für Windows mit C ++ 11 / Qt entwickelt.

Zuerst wollte ich QThread verwenden, aber es scheint mir, dass QThread nicht erlaubt, so viele Dinge wie std :: thread zu tun, zum Beispiel beim Lesen von "C ++ Concurrency in Action" von Anthony Williams sah ich, dass es möglich war, einen std :: -Thread zu fragen, um eine Funktion von einem anderen Thread auszuführen, indem man etwas wie std::thread t1(&Class::function, this, ...); macht, was mit QThread nicht möglich zu sein scheint.

Der Mechanismus, den ich am liebsten haben möchte, ist eine Art zu sagen, ob ich möchte, dass eine Funktion im aktuellen Thread oder in einem anderen Thread ausgeführt wird.

Welchen würden Sie wählen und warum?

    
ElevenJune 27.10.2016, 12:40
quelle

3 Antworten

9

QThread ist nicht nur ein Thread, sondern auch ein Thread-Manager. Wenn dein Thread Qt spielen soll, dann ist QThread der richtige Weg. Qt ist ereignisgesteuert, genau wie die meisten modernen Programme. Das ist etwas komplexer und flexibler als "mach einen Thread eine Funktion ausführen".

In Qt würden Sie normalerweise einen Worker zusammen mit einem QThread erstellen, den Worker zu diesem Thread verschieben, dann wird jede vom Ereignissystem für dieses Worker-Objekt aufgerufene Funktion in dem Thread ausgeführt, in dem das Worker-Objekt Affinität hat zu.

Sie können also Ihre Funktionalität in verschiedene Worker-Objekte kapseln, sagen wir SafetyChecker , Printer , ServoDriver , JetDriver und so weiter, erstellen Sie jeweils eine Instanz, verschieben Sie sie in einen dedizierten Thread und Sie werden eingestellt . Sie können immer noch Funktionen aufrufen, die "blockieren" anstatt feinkörnige Ereignisse zu verwenden, und Atomics oder Mutexe verwenden, um eine Synchronisation zwischen Threads durchzuführen. Es ist nichts falsch daran, solange Sie den Haupt- / GUI-Thread nicht blockieren.

Wahrscheinlich möchten Sie Ihren Druckercode nicht ereignisgesteuert machen, da in einem Multithread-Szenario Warteschlangenverbindungen auftreten, die geringfügig langsamer sind als direkte Verbindungen oder sogar virtueller Versand. So sehr, dass Sie, wenn Sie Ihr Multithreading zu feinkörnig machen, wahrscheinlich einen großen Leistungseinbruch erleben werden.

Abgesehen davon hat die Verwendung von Qt's Nicht-GUI-Zeug seine eigenen Vorzüge, es wird Ihnen erlauben, ein saubereres und flexibleres Design viel einfacher zu machen, und Sie werden immer noch die Vorteile von Multithreading bekommen, wenn Sie Dinge richtig implementieren. Sie können immer noch einen ereignisgesteuerten Ansatz verwenden, um das Ganze zu verwalten, es wird wesentlich einfacher sein, als nur std::thread zu verwenden, was ein viel niedrigeres Konstrukt ist. Sie können den ereignisgesteuerten Ansatz zum Einrichten, Konfigurieren, Überwachen und Verwalten des Entwurfs verwenden, während die kritischen Teile in Blockierfunktionen in Hilfs-Threads ausgeführt werden können, um eine feinkörnige Steuerung bei möglichst geringem Synchronisierungsaufwand zu erreichen.

Zur Klarstellung - die Antwort konzentriert sich nicht auf die asynchrone Aufgabenausführung, da die anderen beiden Antworten dies bereits tun, und weil asynchrone Aufgaben, wie ich in den Kommentaren erwähnte, nicht wirklich für Steuerungsanwendungen gedacht sind. Sie eignen sich für die Ausführung von kleinen Aufgaben, die immer noch mehr Zeit benötigen, als Sie den Hauptthread blockieren möchten. Als empfohlene Richtlinie sollte alles, was mehr als 25 ms benötigt, bevorzugt asynchron ausgeführt werden. Während das Drucken etwas Minuten oder sogar Stunden dauern kann, bedeutet dies, dass kontinuierlich Steuerfunktionen parallel und unter Verwendung von Synchronisation ausgeführt werden. Asynchrone Tasks geben Ihnen keine Garantie für Leistung, Latenz und Reihenfolge für Steueranwendungen.

    
dtech 27.10.2016, 13:23
quelle
6

QThread ist schön, wenn Sie den Thread in das Qt-System integrieren möchten (wie zum Beispiel Signale ausgeben oder Verbindungen zu bestimmten Steckplätzen herstellen)

Obwohl das Layout von QThread immer noch so gemacht wird, funktioniert es mit "altem" c ++. Sie müssen eine Klasse und all diesen Overhead (Code und Typisierung) nur zum Ausführen in einem Thread erstellen.

Wenn du einfach nur einen Thread starten willst, denke ich, dass c ++ 11 std::thread weniger ausführlich ist / Code, den du schreiben musst. Sie können einfach einen Lambda oder Funktionszeiger verwenden und so viele Argumente angeben, wie Sie möchten. Für einfaches Threading würde ich die C ++ 11 Threads über die QThreads vorschlagen.

Natürlich kann es eine Frage der Meinung sein, welche von denen, die Sie bevorzugen.

Obwohl Qt mehrere verschiedene High-Level-Thread-Objekte hat, tut dies C ++ nicht. Vielleicht möchten Sie sich diese ansehen, wenn Sie einige von denen anstelle eines einfachen Threads benötigen, oder vielleicht brauchen Sie gar keinen grundlegenden Thread, aber diese passen Ihnen besser.

Wie ein QThreadPool oder einfach ein QTimer , wenn Sie auf etwas warten müssen. Hier lesen Sie etwas über die Alternativen in Qt thread.

QConcurrent kommt auch näher an c ++ 11 future und async und hat auch optionale threadpools, wo es laufen kann.

    
Hayt 27.10.2016 12:56
quelle
6

Das größte Problem mit std::thread und QThread ist, dass es genau das tut, was es verspricht: Er erstellt einen Thread für Sie, einen Thread, der wahrscheinlich nur eine Sache erledigt. Das Ausführen einer Funktion "gleichzeitig" mit std::thread ist sehr verschwenderisch: Threads sind teure Ressourcen, daher ist die Erstellung eines "nur" zum Ausführen einer Funktion normalerweise übertrieben.

Während std::thread t1(&Class::function, this, ...) nett aussieht und alles, ist es in der Regel eine vorzeitige Pessimisierung und es als eine universelle Art und Weise "Dinge gleichzeitig zu tun" vorschlagen, ist IMHO falsch. Du kannst es besser machen.

  1. Wenn Sie eine Funktion / einen Funktor / eine Methode gleichzeitig in einem Arbeitsthread ausführen möchten, verwenden Sie QtConcurrent::run oder std::async .

    QtConcurrent::run verwendet standardmäßig den Standard-Thread-Pool. Sie können auch eine eigene Instanz von QThreadPool übergeben. Ein typischer Fall wäre die Verwendung des Standard-Thread-Pools für CPU-gebundene Aufgaben, z. Berechnungen, Bildtransformationen, Rendering usw., und verwenden Sie einen dedizierten, größeren I / O-Thread-Pool für Operationen, die aufgrund von Einschränkungen der APIs, die Sie verwenden müssen, blockieren (zB bieten viele Datenbankbibliotheken nur blockierende APIs an Designs sind grundsätzlich gebrochen). Beispiel:

    %Vor%
  2. Wenn du QObject live in einem anderen Thread haben willst (vielleicht mit anderen Objekten zusammenlebst), verwende QThread und bewege dann dein Objekt mit moveToThread zu diesem Thread.

    Es ist ein Idiom, ein Signal vom Worker-Thread zu senden, um Thread sicher an den Haupt-Thread zu übergeben. Z.B. Angenommen, Sie möchten eine reaktionsfähige GUI haben und möchten Bilder von der Festplatte in einem Arbeitsthread laden:

    %Vor%
Kuba Ober 27.10.2016 13:25
quelle

Tags und Links