スレッドとQObject
QThread はQObject を継承しています。スレッドの実行開始や終了を示すシグナルをエミットし、いくつかのスロットも提供します。
さらに興味深いのは、QObjectが複数のスレッドで使用でき、他のスレッドのスロットを呼び出すシグナルを発行したり、他のスレッドに「存在する」オブジェクトにイベントを送信したりできることです。これは、各スレッドが独自のイベントループを持つことが許可されているため可能です。
QObjectの再入可能性
QObject は再入可能です。QTimer 、QTcpSocket 、QUdpSocket 、QProcess など、GUI 以外のサブクラスのほとんども再入可能であり、これらのクラスを複数のスレッドから同時に使用することが可能です。 ただし、これらのクラスは単一のスレッド内での作成および使用を前提として設計されている点に注意してください。あるスレッドでオブジェクトを作成し、別のスレッドからその関数を呼び出すことが正常に動作する保証はありません。留意すべき制約が3つあります:
- QObject の子オブジェクトは、常に親オブジェクトが作成されたスレッド内で作成されなければなりません。これは、とりわけ、QThread オブジェクト(
this)を、そのスレッド内で作成されるオブジェクトの親として渡してはならないことを意味します(QThread オブジェクト自体が別のスレッドで作成されているためです)。 - イベント駆動型オブジェクトは、単一のスレッド内でのみ使用できます。具体的には、これはタイマー機構およびnetwork module に適用されます。例えば、object's thread ではないスレッド内でタイマーを開始したり、ソケットを接続したりすることはできません。
- QThread を破棄する前に、そのスレッド内で作成されたすべてのオブジェクトが確実に破棄されていることを確認する必要があります。これは、run()の実装内でオブジェクトをスタック上に作成することで簡単に実現できます。
QObject は再入可能ですが、GUIクラス、特にQWidget およびそのすべてのサブクラスは再入可能ではありません。これらはメインスレッドからのみ使用できます。前述の通り、QCoreApplication::exec()もそのスレッドから呼び出す必要があります。
実際には、メインスレッド以外のスレッドでGUIクラスを使用できないという制限は、処理に時間がかかる操作を別のワーカースレッドに委ね、ワーカースレッドの処理が完了した時点でメインスレッドで結果を画面に表示することで、容易に回避できます。これは、マン デルブロの例 やBlocking Fortune Clientの例の実装で採用されているアプローチです。
一般的に、QApplication よりも前に QObject を作成することはサポートされておらず、プラットフォームによっては終了時に予期せぬクラッシュを引き起こす可能性があります。これは、QObject の静的インスタンスもサポートされていないことを意味します。適切に構成されたシングルスレッドまたはマルチスレッドのアプリケーションでは、QApplication を最初に作成し、最後に破棄するようにする必要がありますQObject 。
スレッドごとのイベントループ
各スレッドは独自のイベントループを持つことができます。最初のスレッドは、QCoreApplication::exec() を使用してイベントループを開始します。また、単一ダイアログの GUI アプリケーションの場合、QDialog::exec() を使用することもあります。他のスレッドは、QThread::exec() を使用してイベントループを開始できます。QCoreApplication と同様に、QThread はexit(int) 関数とquit() スロットを提供します。
スレッド内のイベントループにより、そのスレッドは、イベントループの存在を必要とする特定の非GUI Qtクラス(QTimer 、QTcpSocket 、QProcess など)を使用できるようになります。また、任意のスレッドからのシグナルを特定のスレッドのスロットに接続することも可能になります。これについては、以下の「スレッド間のシグナルとスロット」のセクションで詳しく説明します。

QObject のインスタンスは、それが作成されたスレッド内に存在するとされます。そのオブジェクトに対するイベントは、そのスレッドのイベントループによってディスパッチされます。QObject が存在するスレッドは、QObject::thread() を使用して取得できます。
QObject::moveToThread() 関数は、オブジェクトとその子オブジェクトのスレッドアフィニティを変更します(オブジェクトに親がある場合、そのオブジェクトを移動することはできません)。
オブジェクトを所有するスレッド以外のスレッドからQObject に対してdelete を呼び出すこと(または他の方法でオブジェクトにアクセスすること)は、その時点でオブジェクトがイベントを処理していないことが保証されない限り、安全ではありません。 代わりに `QObject::deleteLater()` を使用すると、`DeferredDelete ` イベントが投稿され、オブジェクトのスレッドのイベントループが最終的にそれを取得します。デフォルトでは、QObject を所有するスレッドは、QObjectを作成したスレッドですが、QObject::moveToThread() が呼び出された後はそうではありません。
イベントループが実行されていない場合、イベントはオブジェクトに配信されません。例えば、あるスレッドでQTimer オブジェクトを作成しても、exec()を呼び出さなければ、そのQTimer はtimeout()シグナルを放出することはありません。deleteLater()を呼び出しても同様に機能しません。(これらの制限はメインスレッドにも適用されます。)
スレッドセーフな関数 `QCoreApplication::postEvent()` を使用すれば、いつでも、どのスレッドのどのオブジェクトに対しても手動でイベントを投稿できます。イベントは、そのオブジェクトが作成されたスレッドのイベントループによって自動的にディスパッチされます。
イベントフィルタはすべてのスレッドでサポートされていますが、監視するオブジェクトは監視対象のオブジェクトと同じスレッドに存在しなければならないという制限があります。同様に、QCoreApplication::sendEvent() は(postEvent() とは異なり)、関数が呼び出されたスレッド内に存在するオブジェクトへのイベントディスパッチにのみ使用できます。
他のスレッドからの QObject サブクラスへのアクセス
QObject およびそのすべてのサブクラスは、スレッドセーフではありません。これにはイベント配信システム全体が含まれます。別のスレッドからオブジェクトにアクセスしている間にも、イベントループがQObject のサブクラスにイベントを配信している可能性があることを念頭に置いておくことが重要です。
現在のスレッドに存在しないQObject サブクラスの関数を呼び出し、そのオブジェクトがイベントを受信する可能性がある場合は、QObject サブクラスの内部データへのすべてのアクセスをミューテックスで保護する必要があります。そうしないと、クラッシュやその他の予期しない動作が発生する可能性があります。
他のオブジェクトと同様に、QThread オブジェクトは、そのオブジェクトが作成されたスレッド内に存在し、QThread::run() が呼び出された際に作成されるスレッド内には存在しません。メンバー変数をミューテックスで保護しない限り、QThread のサブクラスでスロットを提供することは、一般的に安全ではありません。
一方、シグナルの発信はスレッドセーフであるため、QThread::run() の実装からシグナルを発信することは安全です。
スレッド間のシグナルとスロット
Qt は、以下のシグナル・スロット接続タイプをサポートしています。
- Auto Connection (デフォルト) シグナルが、受信オブジェクトがアフィニティを持つスレッド内で発火された場合、その挙動は「ダイレクト接続」と同じになります。それ以外の場合は、「キュー接続」と同じ挙動となります。
- Direct Connection シグナルが発信されると、スロットは直ちに呼び出されます。スロットは発信元のスレッドで実行されますが、これは必ずしも受信側のスレッドとは限りません。
- Queued Connection スロットは、制御が受信側のスレッドのイベントループに戻ったときに呼び出されます。スロットは受信側のスレッドで実行されます。
- Blocking Queued Connection スロットはキュー付き接続と同様に呼び出されますが、スロットが戻るまで現在のスレッドがブロックされる点が異なります。
注: このタイプを使用して 同じスレッド内のオブジェクトを接続すると、デッドロックが発生します。
- Unique Connection この動作は「自動接続」と同じですが、既存の接続と重複しない場合にのみ接続が確立されます。つまり、同じオブジェクトのペアに対して、同じシグナルがすでに同じスロットに接続されている場合、接続は確立されず、connect() は
falseを返します。
接続タイプは、connect() に追加の引数を渡すことで指定できます。送信者と受信者が異なるスレッドに存在する場合、受信者のスレッドでイベントループが実行されていると、直接接続を使用することは安全ではありません。これは、別のスレッドに存在するオブジェクトに対して関数を呼び出すことが安全でないのと同じ理由によるものです。
QObject::connect() 自体はスレッドセーフです。
マンデルブロの例では、ワーカースレッドとメインスレッド間の通信にキュー接続を使用しています。メインスレッドのイベントループ(ひいてはアプリケーションのユーザーインターフェース)がフリーズするのを防ぐため、マンデルブロフラクタルの計算はすべて別のワーカースレッドで行われます。 フラクタルのレンダリングが完了すると、そのスレッドはシグナルを発行します。
同様に、Blocking Fortune Client の例では、TCP サーバーと非同期に通信するために別のスレッドを使用しています。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.