【C++学習|豆知識】C++20のstd::jthreadで実現する、安全でモダンなスレッド管理

導入

マルチスレッドプログラミングにおいて、スレッドの終了処理(join)を忘れることは、プログラムのクラッシュや予期せぬ終了を引き起こす重大なバグの温床でした。C++20で導入された std::jthread は、デストラクタで自動的に終了待ちを行うことで、これらのリスクを解消し、より安全で簡潔な並列処理の実装を可能にします。

基礎知識

これまでの std::thread では、スレッドを起動した後に join()(終了待ち)または detach()(切り離し)を明示的に呼び出す必要がありました。もしこれらを怠ったままスレッドオブジェクトが破棄されると、std::terminate() が呼ばれ、プログラムが強制終了してしまいます。std::jthread はこの問題を解決するために、デストラクタ内で自動的に終了を待機する仕組みを備えています。また、新たに std::stop_token を用いることで、スレッドに対して安全に停止を要求できるようになりました。

実装/解決策

std::jthread を活用する際は、スレッド関数側で std::stop_token を引数として受け取ることが推奨されます。スレッド内のループ処理などで st.stop_requested() を定期的にチェックすることで、外部からの停止要求を適切に処理できます。これにより、例外発生時やオブジェクトの生存期間終了時に、安全かつ確実にスレッドを終了させることが可能です。

サンプルプログラム

以下のコードは、バックグラウンドで定期的になんらかの処理を行い、メインスレッドからの停止要求に応じて安全に終了するプログラム例です。

include
include include

int main() {
// std::jthreadを作成し、ラムダ式で処理を定義
// 引数にstd::stop_tokenを渡すことで、外部からの停止要求を受け取れる
std::jthread worker([](std::stop_token st) {
int count = 0;
// stop_requested()がtrueになるまで処理を継続する
while (!st.stop_requested()) {
std::cout << "スレッド実行中: " << ++count << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(500)); } std::cout << "スレッドの終了処理を実行中..." << std::endl; }); // メインスレッドで少し待機 std::this_thread::sleep_for(std::chrono::seconds(3)); // ここでスコープを抜けるか、明示的にrequest_stopを呼ぶと // jthreadのデストラクタが自動的にjoinを呼び出す std::cout << "メインスレッドから停止を要求" << std::endl; return 0; }

応用・注意点

std::jthread は非常に強力ですが、注意点も存在します。デストラクタが終了を待機するため、重い処理を行っているスレッドでは、オブジェクトが破棄されるタイミングでメインスレッドがブロックされる(処理が止まる)可能性があります。そのため、長時間の処理を伴う場合は、必ず stop_token による停止処理を適切に実装し、スレッドが速やかに終了できる状態を維持してください。また、明示的に request_stop() を呼び出すことで、デストラクタを待たずに任意のタイミングで終了させることも可能です。これらを意識することで、堅牢なマルチスレッドアプリケーションを構築できます。

コメント

タイトルとURLをコピーしました