it-swarm.com.de

Qt-Signale (QueuedConnection und DirectConnection)

Ich habe Probleme mit Qt-Signalen.

Ich verstehe nicht, wie DirectConnection und QueuedConnection funktionieren?

Ich wäre dankbar, wenn jemand erklären würde, wann er welche verwenden soll (Beispielcode wäre erwünscht).

40
Nika

Sie werden keinen großen Unterschied feststellen, wenn Sie nicht mit Objekten arbeiten, die unterschiedliche Thread-Affinitäten haben. Nehmen wir an, Sie haben QObjects A und B und beide sind an unterschiedliche Threads gebunden. A hat ein Signal namens somethingChanged() und B hat einen Steckplatz namens handleChange().

Wenn Sie eine direkte Verbindung verwenden 

connect( A, SIGNAL(somethingChanged()), B, SLOT(handleChange()), Qt::DirectConnection );

die Methode handleChange() wird tatsächlich im Thread A ausgeführt. Im Grunde ist es so, als würde das Aussenden des Signals die Slot-Methode "direkt" nennen. Wenn B::handleChange() nicht threadsicher ist, kann dies zu (schwer zu lokalisierenden) Fehlern führen. Zumindest verpasst du die Vorteile des zusätzlichen Threads.

Wenn Sie die Verbindungsmethode in Qt::QueuedConnection ändern (oder in diesem Fall Qt entscheiden lassen, welche Methode verwendet werden soll), werden die Dinge interessanter. Unter der Annahme, dass der Thread von B eine Ereignisschleife ausführt, wird das Senden des Signals ein Ereignis in die Ereignisschleife von B posten. Die Ereignisschleife stellt das Ereignis in eine Warteschlange und ruft schließlich die Slot-Methode auf, wenn die Steuerung zu ihr zurückkehrt (dies ist die Ereignisschleife). Dies macht es ziemlich einfach, mit der Kommunikation zwischen/zwischen Threads in Qt umzugehen (wiederum vorausgesetzt, Ihre Threads führen ihre eigenen lokalen Ereignisschleifen aus). Sie müssen sich nicht um Sperren usw. kümmern, da die Ereignisschleife die Slot-Aufrufe serialisiert.

Hinweis: Wenn Sie nicht wissen, wie die Thread-Affinität eines QObjects geändert wird, schauen Sie in QObject::moveToThread. Damit solltest du anfangen.

Bearbeiten

Ich sollte meinen ersten Satz klarstellen. Es macht einen Unterschied, wenn Sie angeben eine in der Warteschlange befindliche Verbindung festlegen - selbst für zwei Objekte in demselben Thread. Das Ereignis wird weiterhin in der Ereignisschleife des Threads angezeigt. Der Methodenaufruf ist also immer noch asynchron, was bedeutet, dass er auf unvorhersehbare Weise verzögert werden kann (abhängig von anderen Ereignissen, die die Schleife möglicherweise verarbeiten muss). Wenn Sie jedoch keine Verbindungsmethode angeben, wird die direkte Methode automatisch für Verbindungen zwischen Objekten in demselben Thread verwendet (zumindest in Qt 4.8).

70
Jacob Robbins

zusätzlich zu Jacob Robbins Antwort:

die Aussage "Sie werden keinen großen Unterschied feststellen, wenn Sie nicht mit Objekten arbeiten, die unterschiedliche Thread-Affinitäten haben" ist false;

wenn Sie ein Signal an eine direkte Verbindung innerhalb desselben Threads senden, wird der Slot sofort ausgeführt, genau wie bei einem einfachen Funktionsaufruf.

wenn Sie ein Signal an eine in der Warteschlange befindliche Verbindung innerhalb desselben Threads senden, wird der Aufruf in die Ereignisschleife des Threads aufgenommen, sodass die Ausführung always verzögert erfolgt.

QObject-basierte Klasse hat eine Verbindung zu sich selbst in der Warteschlange

21
t_3

Jacobs Antwort ist großartig. Ich möchte nur ein Vergleichsbeispiel zu Embedded Programming hinzufügen.

Aus einem eingebetteten RTOS/ISR-Hintergrund stammend, war es hilfreich, die Ähnlichkeiten in Qt's DirectConnection mit dem präventiven Verhalten der ISRs und Qts QueuedConnection mit den Warteschlangenmeldungen in einem RTOS zwischen Tasks zu sehen.

Randbemerkung: Da ich von einem Embedded-Hintergrund komme, ist es schwierig, das Verhalten in der Programmierung nicht zu definieren. Ich lasse das Argument nie als Auto, aber das ist nur eine persönliche Meinung. Ich ziehe es vor, alles explizit zu schreiben, und das wird manchmal schwierig!

0
user3934527