QThreads, QObject und Sleep-Funktion

8

Das Problem, auf das ich gestoßen bin, ist, dass ich beschlossen habe, QThreads so zu implementieren, wie es eigentlich sein sollte, basierend auf zahlreichen Artikeln:
Ссылка
Ссылка

und Problem bei der Hand ist, dass, da der Algorithmus in separaten QObject (umhüllt in QThread ) ausgeführt wird. Wie kann ich etwas wie Thread::Sleep oder etw. nennen? Irgendwelche Ideen?

Eine kleine Beschreibung der Software. Grundsätzlich löst meine Anwendung TSP (Travelling salesman problem). Bei der Suche speichert es alle Zustände in der Geschichte als frames .. (wie visuelle Rahmen). Die Suchalgorithmen werden auf einem Thread ausgeführt. Hauptthread ist die Handhabung mit der GUI. Dann gibt es den Mediaplayer like-Thread, der Main thread sagt, welcher Frame auf dem Bildschirm angezeigt werden soll. Wo kommt der Schlaf her? In gui gibt es einen Schieberegler, den Benutzer verwenden können, um schnell vorzugehen oder in normaler Geschwindigkeit zu gehen .. dieser Schieberegler teilt via Signal-Slot zu Mediaplayer thread, um schneller oder langsamer zu gehen.

    
Erich Jagomägis 27.05.2012, 19:04
quelle

3 Antworten

6

Was wir gemacht haben, ist im Grunde so etwas wie: (geschrieben von Erinnerung, weil ich unseren Code nicht auf diesem Computer ausgecheckt habe)

%Vor%

Der Schlüssel ist, dass die Funktion QThread::sleep den aufrufenden Thread in den Ruhezustand versetzt, nicht die Three, die durch die QThread -Instanz repräsentiert wird. Erstellen Sie einfach einen Wrapper, der ihn über eine benutzerdefinierte QThread - Unterklasse aufruft.

Leider ist QThread ein Durcheinander . Die Dokumentation sagt Ihnen, es falsch zu benutzen. Ein paar Blogposts, wie Sie herausgefunden haben, sagen Ihnen einen besseren Weg, aber dann können Sie keine Funktionen wie sleep , aufrufen, die eigentlich niemals ein geschütztes Thread-Mitglied sein sollten .

Und das Beste von allem, sogar egal, wie Sie QThread verwenden, ist es so konzipiert, dass es emuliert wird, was wahrscheinlich die schlechteste Thread-API ist, die jemals von Java entwickelt wurde. Im Vergleich zu etwas gesund, wie boost::thread , oder noch besser, std::thread , ist es aufgebläht, überkompliziert und unnötig schwer zu bedienen und erfordert eine erschreckende Menge an Standardcode.

Dies ist wirklich einer der Orte, an denen das Qt-Team es blies. Große Zeit.

    
jalf 27.05.2012 19:11
quelle
4

Die einfache Antwort: Sie sollten keinen asynchronen Code vom Ende bis zum Ende blockieren. Jeder Event-Handler und jede Slot-Implementierung in einem QObject soll seine Aufgabe erledigen und so schnell wie möglich zurückgeben. Es sollte nicht so viel tun, um zu warten oder zu schlafen. Mehr darüber in dieser Zeile zu finden, siehe Miro Sameks Ich hasse RTOS .

>

Für eine viel bessere Implementierung, die aus dem obigen folgt, finden Sie stattdessen diese Antwort . Die folgenden Makro-Tricks werden am besten den armen Seelen überlassen, die an C festhalten.

Ich habe ein Beispiel angefügt, wie man es zumindest vom Standpunkt des Codes aus richtig macht. Wenn Sie eine echte Implementierung wünschen, schauen Sie nicht weiter als Boost's stackless coroutines .

Die Makrotrickerei ist syntaktischer Zucker - sie macht die Technik schmackhafter (Boost macht es besser als ich unten). Ob Sie Makros verwenden oder die Methoden explizit ausschreiben, bleibt Ihnen überlassen. Die Syntax ist nicht was behauptet wird, der "richtige Weg" zu sein. Ich bin nicht der Einzige, der solche Preprozessor-Tricks einsetzt . Fehlend ist die Unterstützung von geschachtelten Funktionsaufrufen und mehrere "Threads" von Ausführung von Ausführung bis zur Fertigstellung innerhalb eines QObject . Das Beispiel zeigt Code für nur einen "Thread" und nur eine Ebene von asynchronen Funktionsaufrufen. Stackless Python bringt dies zur logischen Schlussfolgerung.

Sie werden dieses Muster in Ihrem gesamten Code sehen, wenn Sie es asynchron schreiben. Das SLEEP -Makro ist Syntax Sugar, um den Code leichter nachvollziehbar zu machen. Es gibt keinen wirklich sauberen Weg, um es ohne ein Hacky-Makro in C ++ zu schreiben, wo die Syntax nicht übertrieben wäre. Sogar ab C ++ 11 hat die Sprache keine eingebaute Unterstützung für die Ausbeute. Siehe Warum wurde die Rendite nicht zu C ++ 0x hinzugefügt? . p>

Dies ist wirklich nicht blockierender Code. Sie werden sehen, dass das periodische Timer-Ereignis ausgelöst wird, während Sie "schlafen". Beachten Sie, dass dieses kooperative Multitasking einen viel geringeren Aufwand als Thread / Prozess-Switches hat, die vom Betriebssystem ausgeführt werden. Es gibt einen Grund, warum 16-Bit-Windows-Anwendungscode auf diese Weise geschrieben wurde: Er funktioniert ziemlich gut, selbst auf mageren Hardware.

Beachten Sie, dass dieser Code nicht eine QThread benötigt und tatsächlich keine QThread verwendet. Wenn Sie jedoch das Objekt in einen Thread mit hoher Priorität verschieben, werden die Verzögerungen angezeigt wird weniger Verbreitung haben.

Die Implementierung des Qt-Timers ist schlau genug, um den Timer-Tick-Zeitraum unter Windows zu verkürzen, wenn der Zeitraum "kurz" ist. Sie können den plattformspezifischen Code verwenden, den ich unten zeige, aber es sollte davon abgeraten werden. In Qt 5 starten Sie einfach einen Qt::PreciseTimer Timer. Beachten Sie, dass Sie auf Systemen vor Windows 8 den Stromverbrauch und einen etwas höheren Kernel-Overhead für die Leistung hier ausgleichen. Windows 8, OS X (xnu) und modernes Linux sind ohne Tick und leiden nicht unter solchen Leistungseinbußen.

Ich sollte die klare Präprozessor-Missbrauchsrichtung von Erstellen eines C-Makros mit ## und __LINE__ (Token-Verkettung mit einem Positionierungsmakro) .

Ähnlich wie das Makro SLEEP() können Sie auch ein Makro GOTO() implementieren, um einfache Finite-State-Maschinen zu erhalten, die in einem einfacheren Blockcode-Stil geschrieben sind, aber im Hintergrund asynchron sind. Sie können die Makros ENTER() und LEAVE() verwenden, um Aktionen für Statuseinträge und -ausgänge usw. zu implementieren. Der Code kann jedoch vollständig wie eine Funktion mit blockiertem Stil aussehen. Ich fand es sehr produktiv und einfacher zu folgen als Code ohne syntaktische Zuckerbeschichtung. YMMV. Am Ende hätten Sie etwas, das auf dem Weg zu UML-Statecharts ist, aber mit weniger Overhead (sowohl Laufzeit- als auch Code-Text-weise) als QStateMachine-based -Implementierungen.

Unten ist der Ausgang, die Sternchen sind periodische Timer-Ticks.

%Vor% %Vor% %Vor%     
Kuba Ober 31.05.2012 23:25
quelle
2

Ich stimme mit jalf überein. Ich habe einen Thread, der als eine Art DBUS-Daemon fungiert und auf Nachrichten für immer hören muss. Zwei Dinge zu erwähnen:

jalf hat

%Vor%

Aber das ist nicht MILLISECONDS! QThread :: sleep () benötigt Sekunden. Wenn man diesen Ansatz verfolgt, muss er auch die QThread-Bibliothek enthalten, so dass es einfacher ist, den Aufruf so zu machen:

%Vor%

direkt im Code. Auf diese Weise gibt es keine zusätzliche Header-Datei. Ich habe das ausgeführt und es funktioniert auch wie jalf erklärt. (Den aufrufenden Thread in den Ruhezustand versetzen.)

    
MrUser 22.05.2014 10:20
quelle

Tags und Links