C++ で Future パターン

Future とはスレッドで実行している処理との同期、スレッドからの結果の受領を行うためのパターンです。Future パターンは C++11 から std::future という形で標準ライブラリで提供されていますので、具体例については  cppreference.com  などをご参照下さい。

C++ でマルチスレッドデザインパターン

 

C++ で Producer-Consumer パターン

Producer-Consumer とはデータを生産する Producer スレッドとデータを消費する Consumer スレッドがキューを介してデータをやり取りするパターンです。

以下の例では、Producer 側からキューに追加された文字列を Consumer スレッドで取り出して標準出力に出力しています。

Producer スレッドはキューにデータを積む際に Consumer スレッドを起床させ、Consumer スレッドはキューが空になるとブロックされ sleep 状態に入ります。この動作は Garded Suspension パターンそのもので、Producer-Consumer パターンは下位レベルで Garded Suspension パターンを利用していると言えます。 (実際以下の例も Garded Suspension パターンで挙げた例と殆ど同じ内容ですが、スレッドが複数になっている点が異なります)

実際に使用すると以下のようになります。

今回は Producer 側はメインスレッド1つのみですが、当然 Producer 側が複数スレッドになるパターンもあり得ます。

ちなみに上記の例でもスレッドをお行儀良く終了させるために  Two-Phase Termination パターン を併用しています。

C++ でマルチスレッドデザインパターン

C++ で Two-Phase Termination パターン

Two-Phase Termination とは外部からスレッドに対して終了要求を送り、スレッドが自身のタイミングの良い所で処理を終える事で安全にスレッドの終了を行うためのパターンです。

C++ の std::thread ではスレッドを強制終了させるような手段は用意されていないようですが、一般に Two-Phase Termination を行わずに外部からスレッドを強制終了するなどした場合、データの不整合や、リソースリークなどが発生する可能性がありますので大変重要なパターンだと思います。

C++ でマルチスレッドデザインパターン

C++ で Guarded Suspention パターン

Guarded Suspention とは、ある条件が整うまでスレッドの実行を block するというパターンです。 C++ の標準ライブラリで condition variable が提供されていますので、そのまま Guarded Suspention パターンに利用することができます。

以下の例はキューに追加された文字列をスレッドで取り出して標準出力に出力する例です。 Printer というクラスが内部にスレッドを有しており、append で文字列が追加された際にスレッドを起床させて処理をさせます。スレッド側はキューが空になるとブロックされて sleep 状態に入ります。

実際に使用すると以下の用になります。

実装的な注意点として C++ ではメンバー変数の初期化は初期化リストの記述順ではなく宣言順に行われるため、上記の例では std::thread のメンバーの宣言は最後に行うようにする必要があります。スレッドの動作は初期化リストでコンストラクトされた直後に開始されるため、うっかりスレッドが触っているメンバー変数の宣言をスレッドインスタンス宣言の後に行ってしまうとタイミングによって未初期化変数へのアクセスが発生してしまいます。

ちなみに上記の例ではスレッドをお行儀良く終了させるために  Two-Phase Termination パターン を併用しています。

C++ でマルチスレッドデザインパターン

C++ で Immutable パターン

マルチスレッドプログラミングにおいて何故排他制御が必要かと言うと、それは同じデータ(もしくはデータセット)に対して  read と write が同時に起こると不都合なケースがあるからです。

「それならデータを書き込めなくしてしまおう(排他制御のオーバーヘッドもなくなるし)」 と言うのが Immutable パターンです。

このパターンについてはあまり C++ かどうかは関係ないですが、具体的には setter を持たず getter オンリー、かつコンストラクト時にパラメータをすべて初期化するクラスを作ります。このクラスのインスタンスはコンストラクト以降、外部から状態を変更することができませんので排他制御なしに複数のスレッドから 読み放題になります。

C++ でマルチスレッドデザインパターン

C++ でマルチスレッドデザインパターン

C++03 では言語仕様として thread 機能が定義されておらず、プラットフォーム非依存のスレッド関係のコードを書こうとした場合 Boost.Thread などのライブラリを使うしかなかったのですが、ご存知の通り C++11 から thread 関係の機能が標準ライブラリに取り込まれたためより手軽にスレッドの機能が利用できるようになりました (といいつつ、完全にサポートしている処理系はまだないようですが…)

そこで結城浩氏の 「Java言語で学ぶデザインパターン入門 マルチスレッド編 (原著 Concurrent Programming in Java 他)」で紹介されているパターンを C++ でやったらどうなるか紹介してみたいと思います。(題材としている内容は書籍とは違います)

※リンクが無いところはまだ記事書いてないです。すみません…