[C#備忘録]＜独断と偏見まとめ＞MultiThreadデザインパターンのC#版について

# [前回の投稿](http://qiita.com/tassi-yuzukko/items/4953654bad83798d2457)の独断と偏見に満ちたまとめをする

## 注意
完璧に独断と偏見です。

# MultiThreadデザインパターンごとのまとめ
ここに書くのは、基本的には個人的なパターンの使いどころ。
必要であれば補足する。

## １． Single Thread Execution パターン
* メソッドを、スレッドセーフなもの／そうでないもので区別するだけ
    * スレッドセーフでないものは`lock`させましょうねー
* 概念であり、デザインパターンとは言えないだろう

## ２． Immutable パターン
* クラスを、メンバ等の変化がないもの／そうでないもので区別するだけ
    * メンバ等の変化ないものは、クラス自体がスレッドセーフといえる
* これも概念であり、デザインパターンとは言えないだろう

## ３． Guarded Suspension パターン
* スレッド間メッセージキューのパターン
    * メッセージがない間は、受け取り側スレッドを待機させる
    * [`BlockingCollection`](https://msdn.microsoft.com/ja-jp/library/dd997371(v=vs.110).aspx)を使えば、何も考えなくてもメッセージキューが作れる

##### 補足
* 本当の意味は、受け取り側にガード条件を設けて、ガード条件に合致しない場合は、スレッドを待ちにさせる。
* ガード条件が「メッセージが存在するか」という最もシンプルな場合は、上記のメッセージキューに当てはまる。
    * ガード条件が複雑な場合は、`Wait/Pulse`を駆使する必要がある。
    * けど、キューは排他機能付きの~~[`ConcurrentQueue`](https://msdn.microsoft.com/ja-jp/library/dd267265(v=vs.110).aspx)~~[`BlockingCollection`](https://msdn.microsoft.com/ja-jp/library/dd997371(v=vs.110).aspx)を使うべし。

## ４． Balking パターン
* `Guarded Suspension パターン`の亜種
* ガード条件に合致しないときは、処理を中止する
    * 中止することで、パフォーマンス向上を図る
* `Guarded Suspension パターン`に、不要だったら処理を中止するという機能を付加するというイメージ

## ５． Producer-Consumer パターン
* `Guarded Suspension パターン`で、メッセージの送り手と受け手の両方にガード条件が存在するパターン
    * 例えば、メッセージキューでキューの上限が決まっていて、送り手側でキューが上限に達していたら待つ処理を追加するときに用いる
* つまり、`Guarded Suspension パターン`に機能を付加するイメージ

## ６． Read-Writer Lock パターン
* ２種類の`lock`を使用して排他制御する
    * 書き込み用ロック：ロック中は、書き込みも読み込みもできない
    * 読み込み用ロック：ロック中は、読み込みはできるが、書き込みはできない
* ロックが不要な処理に対してはロック条件を緩くすることで、パフォーマンス向上を図る
* [`ReaderWriterLockSlim`](https://msdn.microsoft.com/ja-jp/library/system.threading.readerwriterlockslim(v=vs.110).aspx)を使用すれば容易に実現できる

## ７． Thread-Per-Message パターン
* たぶん、受け取り用常駐スレッドが存在しないただの非同期処理
    * 非同期処理で実行した結果は特に待たない
    * つまり、`Task.Run()`して`await`や`Wait`しないパターン
* デザインパターンとして考えなくてよいだろう

## ８． Woker Thread パターン
* `Producer-Consumer`パターンのスレッドプール使用版
* C#ではスレッドは`Task`＝スレッドプールを使用するのがデファクトスタンダードなので、`Producer-Consumer`パターンと同一視して問題ないと思う

## ９． Future パターン
* 非同期処理だけど、クライアント側の好きなタイミングで結果を受け取る
    * 待ち受ける際、すぐにクライアント側に制御が返る（引換券）
    * 結果は後から受け取る
* `async/await`のことと思ってたけど、必ずしもそうではない。
    * 開始と待ち受けが、異なるメソッドの時は`Task.Start`と`Task.Wait`という使用する。
* クライアント側はマルチスレッドを意識しない（あたかもシングルスレッドで動作しているかのよう）というメリットもある

##### 補足
一応補足しておくと、`Future`パターンは`Thread-Per-Message`パターンの亜種

## １０． Two-Phase Termination パターン
* スレッド終わるときに、後始末をしてから終わるようにすること
    * ２段階の終了処理
* あたりまえのこと。スレッドのたしなみ
* わざわざデザインパターンという程のものではない

## １１． Thread-Specific Storage パターン
* 使わない。不要。
    * スレッド固有のコインロッカー。だけど、C#では基本的にスレッドプールで処理する（＝スレッドを使いまわす）ので、スレッド固有という概念が使えない
    * そもそも、使えなくても何の問題もない

## １２． Active Object パターン
* `Futureパターン`に`WokerThreadパターン`を組み合わせたもの
* ごちゃごちゃしているけど、結果的に`Future`パターンとの違いは、  
  「固定されたスレッドがワーカーとして実処理を行う」ということ
* つまり、ワーカースレッドはシングルスレッドで処理する必要がある（例えばスレッドセーフにできないとか）ときに使える
    * クライアントスレッドへはすぐに引換券（疑似結果）が返ってくる。実際の結果は、クライアントスレッド側の好きなタイミング受け取る。
        * 受け取りフラグみたいなのを、ワーカースレッド側でONにして、フラグONでクライアント側は結果格納先にアクセスできるようにする
    * クライアントスレッドはマルチスレッドで動作させて、複数クライアントに対応できる

# まとめのまとめ
以上より、強引にまとめると、覚えておくべきパターンは以下の４通り

* WorkerThreadパターン
    * スレッド間での同期処理
    * 必要であればBalkingの機能を追加する
* Futureパターン
    * 非同期処理をしつつも、クライアント側の好きなタイミングで結果を受け取る
* ActiveObjectパターン
    * Futureパターンにしたいが、処理するスレッドが１つに限定される場合にWorkerThreadパターンを融合する
* Read-Writer Lockパターン
    * 書き込みと読み込みが存在するときの排他制御

（Two-Phase Terminationパターンは重要だが、当たり前のことなのでカウントしていない）