はじめに
C++で新しいスレッドを起動すると、そのスレッド(ワーカースレッド)は、呼び出し元のスレッド(メインスレッド)とは並行して動作します。そのため、メインスレッドがワーカースレッドの処理完了を待たずに先に終了してしまうと、ワーカースレッドは処理の途中で強制的に中断されてしまいます。
ワーカースレッドに割り当てたタスクが、メインスレッドの処理の続きで必要となる結果を計算している場合など、「ワーカースレッドの処理が完全に終わるまで、メインスレッドに待っていてほしい」という場面が必ず出てきます。
この「合流(join)」を実現するのが、.join()
メソッドです。
.join()
を使ったサンプルコード
このコードは、メインスレッドが heavy_calculation
という重い処理を行うワーカースレッドを起動し、.join()
を使ってその処理が完了するのを待ってから、最終的なメッセージを表示します。
完成コード
#include <iostream>
#include <thread>
#include <chrono> // sleep_for を使うために必要
using namespace std;
// ワーカースレッドで実行される、時間のかかるタスク
void heavy_calculation() {
cout << "ワーカースレッド: 重い計算処理を開始します... (3秒かかります)" << endl;
this_thread::sleep_for(chrono::seconds(3));
cout << "ワーカースレッド: 計算処理が完了しました。" << endl;
}
int main() {
cout << "メインスレッド: ワーカースレッドを起動します。" << endl;
// 1. スレッドを生成し、タスクを開始
thread worker(heavy_calculation);
cout << "メインスレッド: ワーカースレッドの終了を待っています..." << endl;
// 2. workerスレッドの処理が完了するまで、ここで処理をブロック(待機)
worker.join();
// 3. worker.join()が完了した後、この行が実行される
cout << "メインスレッド: ワーカースレッドが合流したので、処理を終了します。" << endl;
return 0;
}
実行結果
メインスレッド: ワーカースレッドを起動します。
メインスレッド: ワーカースレッドの終了を待っています...
ワーカースレッド: 重い計算処理を開始します... (3秒かかります)
(約3秒後)
ワーカースレッド: 計算処理が完了しました。
メインスレッド: ワーカースレッドが合流したので、処理を終了します。
コードの解説
thread worker(heavy_calculation);
thread
オブジェクト worker
を生成し、heavy_calculation
関数の実行を新しいスレッドで開始します。この瞬間から、メインスレッドと worker
スレッドは並行して動作します。
worker.join();
この一行が、スレッドの同期を行う核心部分です。
main
スレッドは、worker.join()
の行に到達すると、**実行を一時停止(ブロック)**します。- その間、
worker
スレッドはバックグラウンドでheavy_calculation
の処理を続けます。 heavy_calculation
の処理が全て完了し、worker
スレッドが終了した瞬間に、main
スレッドのブロックが解除され、join()
の次の行から処理が再開されます。
もし worker.join()
の行がなければ、main
スレッドはワーカースレッドの完了を待たずに即座に終了してしまい、heavy_calculation
の処理は途中で打ち切られてしまいます。
まとめ
今回は、std::thread::join()
を使って、別スレッドの処理が完了するのを待機する方法を解説しました。
.join()
を呼び出すと、対象のスレッドが終了するまで、呼び出し元のスレッドは待機する。- これにより、スレッド間の処理の順序を保証できる(例: 計算スレッドが終わってから、結果表示スレッドを動かす)。
std::thread
オブジェクトは、破棄される前に必ず.join()
または.detach()
のどちらかを呼び出す必要がある。
.join()
は、マルチスレッドプログラミングにおいて、スレッド間の同期を取るための最も基本的で重要なメカニズムです。