再入可能性とスレッドセーフ性
このドキュメント全体を通じて、「再入可能」および「スレッドセーフ」という用語は、マルチスレッドアプリケーションでの使用方法を示すために、クラスや関数を識別するために使用されています:
- スレッドセーフな関数は、呼び出し間で共有データを使用する場合でも、共有データへのすべての参照がシリアル化されるため、複数のスレッドから同時に呼び出すことができます。
- 再入可能な関数も、複数のスレッドから同時に呼び出すことができますが、それは各呼び出しが独自のデータを使用する場合に限られます。
したがって、スレッドセーフな関数は常に 再入可能ですが、再入可能な関数が必ずしもスレッドセーフであるとは限りません。
さらに言えば、各スレッドがクラスの異なるインスタンスを使用する限り、そのメンバ関数を複数のスレッドから安全に呼び出せる場合、そのクラスは再入可能であると言えます。一方、すべてのスレッドがクラスの同じインスタンスを使用する場合でも、そのメンバ関数を複数のスレッドから安全に呼び出せる場合、そのクラスはスレッドセーフです。
注:Qt クラスは、複数のスレッドでの使用が意図されている場合にのみ、スレッドセーフであると文書化されています。関数がスレッドセーフまたは再入可能としてマークされていない場合は、異なるスレッドからその関数を使用してはなりません。 クラスがスレッドセーフまたは再入可能として指定されていない場合、そのクラスの特定のインスタンスには異なるスレッドからアクセスしてはなりません。
再入可能性
C++ クラスは、単に自身のメンバデータにのみアクセスするという理由だけで、多くの場合再入可能となっています。他のスレッドが同時にそのクラスの同じインスタンスに対してメンバ関数を呼び出さない限り、どのスレッドでも再入可能なクラスのインスタンスに対してメンバ関数を呼び出すことができます。たとえば、以下の `Counter ` クラスは再入可能です:
class Counter
{
public:
Counter() { n = 0; }
void increment() { ++n; }
void decrement() { --n; }
int value() const { return n; }
private:
int n;
};このクラスはスレッドセーフではありません。複数のスレッドがデータメンバ `n` を変更しようとすると、結果は未定義となるからです。これは、++ および-- 演算子が常にアトミックであるとは限らないためです。実際、これらは通常、次の 3 つのマシン命令に展開されます:
- 変数の値をレジスタに読み込む。
- レジスタの値をインクリメントまたはデクリメントする。
- レジスタの値をメインメモリに書き戻す。
スレッド A とスレッド B が同時に変数の以前の値をロードし、レジスタの値をインクリメントまたはデクリメントして、それをメインメモリに書き戻すと、互いに上書きし合うことになり、変数は 1 回しかインクリメントされません!
スレッドセーフ
明らかに、このアクセスはシリアル化する必要があります。つまり、スレッド B が同じ手順を実行する前に、スレッド A が手順 1、2、3 を中断されることなく(アトミックに)実行しなければなりません。その逆も同様です。クラスをスレッドセーフにする簡単な方法は、データメンバーへのすべてのアクセスを `QMutex` で保護することです:
class Counter
{
public:
Counter() { n = 0; }
void increment() { QMutexLocker locker(&mutex); ++n; }
void decrement() { QMutexLocker locker(&mutex); --n; }
int value() const { QMutexLocker locker(&mutex); return n; }
private:
mutable QMutex mutex;
int n;
};QMutexLocker クラスは、コンストラクタ内で自動的にミューテックスをロックし、関数の終了時にデストラクタが呼び出されるとロックを解除します。ミューテックスをロックすることで、異なるスレッドからのアクセスがシリアル化されることが保証されます。 データメンバー `mutex ` は、mutable 修飾子付きで宣言されています。これは、const関数である `value()` 内でミューテックスのロックとロック解除を行う必要があるためです。
Qt クラスに関する注意事項
多くの Qt クラスは再入可能ですが、スレッドセーフには設計されていません。スレッドセーフにするには、QMutex のロックとアンロックを繰り返し行うという余分なオーバーヘッドが発生するためです。例えば、QString は再入可能ですが、スレッドセーフではありません。 複数のスレッドから同時に異なる QString のインスタンスに安全にアクセスすることは可能ですが、複数のスレッドから同時に同じ QString のインスタンスに安全にアクセスすることはできません(QMutex を使用してアクセスを自ら保護する場合を除きます)。
一部の Qt クラスおよび関数はスレッドセーフです。これらは主に、スレッド関連のクラス(例:QMutex )および基本的な関数(例:QCoreApplication::postEvent())です。
注: マルチスレッド分野における用語は 完全に標準化されているわけではありません。POSIXでは、C APIにおいて「再入可能(reentrant)」および「スレッドセーフ(thread-safe)」の定義が多少異なります。Qtと他のオブジェクト指向C++クラスライブラリを併用する場合は、それらの定義を確実に理解しておく必要があります。
© 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.