【ITニュース解説】The Barrier in C++ 20 concurrency - the programmer in me is still thriving...

2025年09月04日に「Dev.to」が公開したITニュース「The Barrier in C++ 20 concurrency - the programmer in me is still thriving...」について初心者にもわかりやすいように丁寧に解説しています。

作成日: 更新日:

ITニュース概要

C++20で導入された`std::barrier`は、複数スレッドの同期を行う機能だ。指定したスレッド数が`wait()`を呼ぶまで待機し、全スレッドが到達後、同時に処理を再開する。`std::latch`に似ているが、再利用可能。記事では、学生クラスのタスク実行を例に、`barrier`を使ったスレッド同期のサンプルコードを紹介している。

ITニュース解説

C++20で導入されたstd::barrierは、複数のスレッド間の同期を実現するための機能だ。これは、ある特定の時点までスレッドの実行を一時停止させ、すべてのスレッドがその時点に到達した後に、それらを同時に再開させるために使用される。std::latchと似ているが、std::barrierは一度使用した後もリセットして再利用できる点が異なる。

std::barrierオブジェクトは、初期化時にカウント数を指定する。このカウントは、バリアに到達する必要のあるスレッドの数を表す。スレッドがバリアに到達すると、arrive_and_wait()メソッドを呼び出す。このメソッドは、カウントがゼロになるまでスレッドをブロックする。カウントがゼロになると、バリアで待機していたすべてのスレッドが解放され、実行を再開する。

std::barrierの主な用途は、並列処理におけるタスクの同期だ。例えば、複数のスレッドが計算を行い、その結果を組み合わせて最終的な結果を得るような場合、すべてのスレッドが計算を終えるまで次の処理に進むことができない。このような場合にstd::barrierを使用することで、各スレッドが安全に結果を共有し、次の段階に進むことができる。また、プロデューサー・コンシューマーモデルや、並列アルゴリズムの実装、競合状態の回避など、さまざまな同期パターンを実現できる。

記事のサンプルコードでは、StudentクラスとclassETCクラスを使用し、学生が課題に取り組む様子をシミュレートしている。

Studentクラスは、学生の名前(name)、課題開始までの待機時間(timeLapseBeforeStarting)、課題完了までの時間(timeToFinish)をメンバ変数として持つ。task()メソッドは、スレッドとして実行されるタスクを表す。このメソッド内で、まずthis_thread::sleep_for()を使って指定された時間だけスレッドを一時停止させる。これは、学生が課題に取り掛かるまでに時間がかかることを模倣している。次に、b.arrive_and_wait()を呼び出し、バリアに到達したことを通知し、他のスレッドがバリアに到達するまで待機する。すべてのスレッドがバリアに到達すると、現在時刻を出力し、再度this_thread::sleep_for()を使って課題の完了までの時間をシミュレートする。最後に、課題が完了したことを出力する。

classETCクラスは、複数の学生に課題を与える役割を担う。giveTaskToStudent()メソッドは、3つのスレッド(Ridit, Ishan, Rajdeepに対応)を作成し、それぞれのスレッドでStudentオブジェクトのtask()メソッドを実行する。各スレッドは、それぞれ異なる待機時間と完了時間を持つ。ref(b)は、バリアオブジェクトbへの参照をスレッドに渡すために使用される。join()メソッドは、スレッドが完了するまでメインスレッドが待機するようにするために使用される。

main()関数では、まずC++のバージョンを確認し、次にstd::barrierオブジェクトbを初期化する。このバリアは3つのスレッドを同期するために使用される。classETCオブジェクトを作成し、giveTaskToStudent()メソッドを呼び出して、学生に課題を与える。

このコードを実行すると、3つのスレッドはそれぞれ指定された待機時間の後、バリアで待機する。すべてのスレッドがバリアに到達すると、同時に課題に取り組み始める。出力結果を見ると、3つのスレッドがほぼ同じ時刻にタスクを開始していることがわかる。これは、std::barrierによってスレッド間の同期が実現されていることを示している。std::barrierを使用しない場合、各スレッドはそれぞれの待機時間の後に独立してタスクを開始するため、開始時刻はばらばらになる。

このように、std::barrierは、複数のスレッドが特定の時点まで処理を進めないようにする必要がある場合に非常に有効だ。並列処理において、スレッド間の同期は重要な課題であり、std::barrierはその解決策の一つとなる。初心者にとっては少し難解かもしれないが、実際にコードを書いて試してみることで、その動作と有用性を理解できるはずだ。