はじめに
C++の std::thread オブジェクトは、生成されると特定のスレッドの実行を管理します。この thread オブジェクトに対して、スレッドの終了を待つ .join() や、スレッドを切り離す .detach() を呼び出すと、オブジェクトはスレッドの管理を手放し、「空」の状態になります。
.joinable() メソッドは、thread オブジェクトが現在、有効なスレッドを管理しているかどうかを調べるためのものです。joinable() が true を返すオブジェクトに対してのみ、.join() や .detach() を安全に呼び出すことができます。
この記事では、joinable() の基本的な使い方と、thread オブジェクトのライフサイクルにおけるその役割の重要性について解説します。
joinable() の状態変化を確認するサンプルコード
このコードは、thread オブジェクトを生成した直後、.join() を呼び出した後、そしてムーブ代入した後の、joinable() の戻り値がどのように変化するかを示します。
完成コード
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
// スレッドで実行する簡単なタスク
void short_task() {
this_thread::sleep_for(chrono::milliseconds(100));
}
int main() {
// 1. スレッドを生成
thread worker(short_task);
// 2. joinable()の確認 (生成直後)
// workerは有効なスレッドを管理しているため、trueを返す
cout << "生成直後 -> worker.joinable(): " << boolalpha << worker.joinable() << endl;
// 3. スレッドの終了を待つ
worker.join();
// 4. joinable()の確認 (join()呼び出し後)
// workerはスレッドの管理を手放したため、falseを返す
cout << "join()後 -> worker.joinable(): " << boolalpha << worker.joinable() << endl;
// NG: joinableでないスレッドにjoin()を呼ぶと、プログラムがクラッシュする
// if (worker.joinable()) {
// worker.join();
// }
return 0;
}
boolalpha: C++のストリームマニピュレータで、bool 値を 1/0 ではなく true/false の文字列として出力させます。
コードの解説と joinable() の重要性
joinable() が true を返す条件
threadオブジェクトが、まだ.join()も.detach()も呼び出されていない、アクティブなスレッドを管理している。- デフォルトコンストラクタで作られた空の
threadオブジェクトではない。 - 他の
threadオブジェクトに**ムーブ(所有権を移動)**させていない。
joinable() が false を返す条件
.join()が既に呼び出された後。.detach()が既に呼び出された後。- デフォルトコンストラクタで生成された
threadオブジェクト。 - 他の
threadオブジェクトにムーブした後の、元のオブジェクト。
デストラクタと joinable() の関係
thread オブジェクトは、そのデストラクタ(オブジェクトが破棄されるとき)が呼び出される際に、自身が joinable() であるかどうかをチェックします。
もし、joinable() が true の状態(つまり、有効なスレッドを管理しているのに、join も detach もされていない状態)でオブジェクトが破棄されると、デストラクタは std::terminate() を呼び出し、プログラム全体を即座に強制終了させます。
これは、管理されていないスレッドが宙ぶらりんになるのを防ぐための、C++の安全機構です。したがって、thread オブジェクトを生成したら、そのスコープを抜ける前に必ず join() または detach() を呼び出す必要があります。
まとめ
今回は、std::thread::joinable() メソッドの役割について解説しました。
joinable()は、そのthreadオブジェクトが.join()や.detach()を呼び出せる状態か (true)、そうでないか (false) を返す。joinable()がtrueのままthreadオブジェクトを破棄すると、プログラムが強制終了する。- したがって、
threadを生成したら、破棄する前に必ずjoin()またはdetach()を呼び出さなければならない。
joinable() を直接 if 文などで使う場面は少ないかもしれませんが、このメソッドが true を返す状態の意味を理解することは、std::thread のライフサイクルを正しく管理し、安全なマルチスレッドプログラムを書く上で非常に重要です。
