web-dev-qa-db-fra.com

Signaux Qt (QueuedConnection et DirectConnection)

J'ai des problèmes avec les signaux Qt.

Je ne comprends pas comment fonctionne DirectConnection et QueuedConnection?

Je serais reconnaissant si quelqu'un expliquerait quand utiliser lequel de ceux-ci (un exemple de code serait apprécié).

40
Nika

Vous ne verrez pas beaucoup de différence si vous ne travaillez pas avec des objets ayant des affinités de fil différentes. Supposons que vous avez QObjects A et B et qu'ils sont tous deux attachés à des threads différents. A a un signal appelé somethingChanged() et B a un emplacement appelé handleChange().

Si vous utilisez une connexion directe 

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

la méthode handleChange() sera effectivement exécutée dans le thread de la A. En gros, c'est comme si émettre le signal appelait la méthode de slot "directement". Si B::handleChange() n'est pas thread-safe, cela peut causer des bogues (difficiles à localiser). À tout le moins, vous manquez les avantages du fil supplémentaire.

Si vous modifiez la méthode de connexion en Qt::QueuedConnection (ou, dans ce cas, laissez Qt décider de la méthode à utiliser), les choses deviennent plus intéressantes. En supposant que le thread de B exécute une boucle d'événement, l'émission du signal publiera un événement dans la boucle d'événement de B. La boucle d'événement met en file d'attente l'événement et appelle finalement la méthode slot chaque fois que le contrôle lui revient (il s'agit de la boucle d'événement). Cela facilite la gestion de la communication entre/parmi les threads dans Qt (encore une fois, en supposant que vos threads exécutent leurs propres boucles d’événements locales). Vous n'avez pas à vous soucier des verrous, etc., car la boucle d'événements sérialise les appels de logements.

Remarque: Si vous ne savez pas comment changer l'affinité de thread d'un QObject, examinez QObject::moveToThread. Cela devrait vous aider à démarrer.

Modifier

Je devrais clarifier ma phrase d'ouverture. Cela fait une différence si vous spécifiez une connexion en file d'attente, même pour deux objets sur le même thread. L'événement est toujours publié dans la boucle d'événements du thread. L'appel de méthode est donc toujours asynchrone, ce qui signifie qu'il peut être différé de manière imprévisible (en fonction de tout autre événement que la boucle peut avoir à traiter). Toutefois, si vous ne spécifiez pas de méthode de connexion, la méthode directe est automatiquement utilisée pour les connexions entre des objets situés sur le même thread (du moins dans Qt 4.8).

70
Jacob Robbins

en plus de Jacob Robbins répondre:

l'affirmation "Vous ne verrez pas beaucoup de différence si vous ne travaillez pas avec des objets ayant des affinités de thread différentes" est faux;

l'émission d'un signal vers une connexion directe au sein du même thread exécutera immédiatement l'emplacement, tout comme un simple appel de fonction.

émettre un signal vers une connexion en file d'attente au sein du même thread mettra l'appel en file d'attente dans la boucle d'événements du thread, ainsi l'exécution always se produira avec un retard.

La classe basée sur QObject a une connexion en file d'attente avec elle-même

21
t_3

La réponse de Jacob est géniale. Je voudrais juste ajouter un exemple comparatif à la programmation intégrée.

Venant d’un arrière-plan RTOS/ISR intégré, il était utile de voir les similitudes entre le comportement DirectConnection to Preemptive de Qt des ISR et les messages QueuedConnection to Queued de Qt dans un RTOS entre tâches.

Note latérale: Venant d’un arrière-plan Embedded, il m’est difficile de ne pas définir le comportement dans la programmation. Je ne quitte jamais l'argument en tant qu'Auto, mais ce n'est qu'un avis personnel. Je préfère que tout soit écrit explicitement, et oui ça devient parfois difficile!

0
user3934527