web-dev-qa-db-ja.com

Qtシグナル(QueuedConnectionおよびDirectConnection)

Qtシグナルに問題があります。

DirectConnectionQueuedConnectionがどのように機能するのか理解できませんか?

これらのどれをいつ使用するかを誰かが説明してくれたらありがたいです(サンプルコードをいただければ幸いです)。

43
Nika

異なるスレッドアフィニティを持つオブジェクトを使用している場合を除き、大きな違いは見られません。 QObjects ABがあり、両方とも異なるスレッドに接続されているとします。 AにはsomethingChanged()と呼ばれる信号があり、BにはhandleChange()と呼ばれるスロットがあります。

直接接続を使用する場合

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

メソッドhandleChange()は、実際にAのスレッドで実行されます。基本的に、信号を発することはスロットメソッドを「直接」呼び出すかのようです。 B::handleChange()がスレッドセーフでない場合、これはいくつかの(見つけにくい)バグを引き起こす可能性があります。少なくとも、余分なスレッドの利点を見逃しています。

接続方法を_Qt::QueuedConnection_に変更する(または、この場合、使用する方法をQtに決定させる)と、事態はさらに面白くなります。 Bのスレッドがイベントループを実行していると仮定すると、シグナルを送信するとBのイベントループにイベントがポストされます。イベントループはイベントをキューに入れ、最終的にコントロールがイベントループに戻るたびに最終的にスロットメソッドを呼び出します。これにより、Qt内のスレッド間の通信を簡単に処理できます(ここでも、スレッドが独自のローカルイベントループを実行していると仮定しています)。イベントループはスロットの呼び出しをシリアル化するため、ロックなどを心配する必要はありません。

注:QObjectのスレッドアフィニティを変更する方法がわからない場合は、_QObject::moveToThread_を調べてください。これで開始できます。

編集

冒頭の文を明確にする必要があります。同じスレッド上の2つのオブジェクトであっても、キュー接続をspecify指定すると、違いが生じます。イベントはまだスレッドのイベントループにポストされます。そのため、メソッド呼び出しはまだ非同期です。つまり、予測できない方法で遅延する可能性があります(ループが処理する必要のある他のイベントに応じて)。ただし、接続方法を指定しない場合、同じスレッド上のオブジェクト間の接続には直接的な方法が自動的に使用されます(少なくともQt 4.8では)。

76
Jacob Robbins

ジェイコブ・ロビンスの答えに加えて:

「異なるスレッドアフィニティを持つオブジェクトを操作しない限り、大きな違いは見られません」というステートメントは、wrong;

同じスレッド内の直接接続に信号を送信すると、単純な関数呼び出しのように、すぐにスロットが実行されます。

同じスレッド内のキューに入れられた接続にシグナルを送信すると、スレッドイベントループに呼び出しがキューイングされるため、実行はalways遅延して発生します。

QObjectベースのクラスにはそれ自体へのキュー接続があります

22
t_3

ジェイコブの答えは素晴らしいです。埋め込みプログラミングに比較例を追加したいだけです。

埋め込まれたRTOS/ISRのバックグラウンドから来て、タスク間でRTOSでISRのプリエンプティブ動作に対するQtのDirectConnectionとキューに入れられたメッセージへのQtのQueuedConnectionの類似性を確認することは役に立ちました。

サイドノート:組み込みのバックグラウンドから来ると、プログラミングで動作を定義しないことは私にとって難しいです。私は議論をオートとは決してしませんが、それは単なる個人的な意見です。私はすべてが明示的に書かれていることを好みます、そしてそれは時々難しくなります!

0
user3934527