スレッド

つっこんでばっかりもなんなので調べた。
たいしてスレッドに詳しいわけでもないので、間違ってるかも。

○スレッドで気をつけなきゃいけないこと
1・クリティカルセクション
基本

2・アウトオブオーダ実行
プロセッサの高速化機能(コンパイラの機能じゃない)
順番通りに実行されないことがある。
メモリバリアで守る。
アウトオブオーダ実行
http://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%A6%E3%83%88%E3%83%BB%E3%82%AA%E3%83%96%E3%83%BB%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E5%AE%9F%E8%A1%8C
メモリバリア
http://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%90%E3%83%AA%E3%82%A2

3・CPUのキャッシュに値が載ってることがある
https://www.microsoft.com/japan/msdn/msdnmag/issues/05/10/MemoryModels/default.aspx
http://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/default.aspx(英語 原文)
http://www.ailight.jp/blog/kazuk/articles/6281.aspx

4・コンパイラの最適化でメモリ読み書きの順序が変わることがある

.Netでは2、3、4はロックをかけとけば大丈夫。
Monitor、Mutex、Semaphoreどれでもいいんだろう。

https://www.microsoft.com/japan/msdn/msdnmag/issues/05/08/Concurrency/#S10

競合を防ぐ一番普通の方法は、インバリアントの壊れているときに、そのインバリアントに関連付けられているメモリに他のスレッドがアクセスしてこないようにロックを使用することです。こうすれば、先に述べた 4 つ目の条件が解消されるので、競合は起こりえません。

最も一般的な種類のロックにはさまざまな名前が付いています。モニタとも、クリティカル セクションとも、ミューテックスとも、バイナリセマフォとも呼ばれることがありますが、名前は違っても基本的な機能は皆同じです。ロックには Enter メソッドと Exit メソッドがあります。どれかスレッドが Enter メソッドをコールすると、他のスレッドが Enter メソッドをコールしようとしても、Exit メソッドへのコールが実行されるまで、最初のスレッド以外のスレッドには待ったがかかります。 Enter メソッドをコールしたスレッドがロックのオーナーとなります。ロックのオーナーではないスレッドが Exit メソッドをコールした場合、それはプログラミングエラーであると見なされます。ロックという機能によって、コードの特定の部分を複数のスレッドで同時に実行できないようにしているのです。

Microsoft .NET Framework のロックは System.Threading.Monitor クラスで実装しています。この Monitor クラスは、インスタンスを定義しないため、少し変わっています。そのわけは、ロック機能が System.Object によって効果的に実装されていて、そのためにどのオブジェクトもロックになれることにあります。次に、totalRequests に関連のある競合をロックで解消する方法を示します。 

コストの高くつくもう 1 つの理由は、プロセス間通信がメモリシステムに及ぼす影響です。プログラムは、ロックを取得した後、その直前に既に別のスレッドに修正された可能性のあるメモリにアクセスする確率が非常に高いです。このスレッドが別のプロセッサ上で実行された場合は、他すべてのプロセッサ上で保留になっているすべての書き込み処理を事前にフラッシュしておかないと、最新のスレッドから更新内容が確認できません。この処理に要するコストは、メモリシステムのしくみと、フラッシュする必要のある書き込み処理の個数とによって大きく左右されます。このコストは、最悪時には事によると数百サイクル以上とかなり高くつくことがあります。

・優先順位の逆転
http://ja.wikipedia.org/wiki/%E5%84%AA%E5%85%88%E9%A0%86%E4%BD%8D%E3%81%AE%E9%80%86%E8%BB%A2
前の仕事で処理によってスレッドの優先順位を変えるのをやめといた理由がこれ
バッチ処理するプログラムでのデータベース更新や、帳票系のプログラムのデータ作成が重くて、他の処理が遅くなることがあった。
大きな更新処理や、帳票出力は時間がかかってもまぁしょうがないけど、テキストボックスを抜けた時のチェックとか、伝票の登録が遅いと文句いわれる。
なら、バッチ更新とか帳票出力のスレッドのプライオリティを下げてやろうかと思ったんだけど
1・バッチ更新プログラムAが走る(優先度 低)
2・AがDBのロックとる
3・伝票更新Bが走る(優先度 高)
4・Bでも2でAがとってるロックが欲しいけど、とれないから待つ
5・Aのスレッドは優先順位が低いから処理をBに譲る
6・Bは処理を譲られたけどやっぱりロックがとれないから待つ
以下ループ
なっちゃったらどーしよ、ということでスレッドの優先順位はいじらないことにした。

.Netだと優先順位の高いスレッドがすべて終わるまで、優先順位の低いスレッドは実行権を譲っちゃいそうだったので。
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpguide/html/cpconschedulingthreads.asp
DBアクセスとかIOが絡むとまた違うのかもしれないけど、DBアクセスのミドルウェアによってどうなるのかわかんないし。


○よくわからないこと
https://www.microsoft.com/japan/msdn/msdnmag/issues/05/10/MemoryModels/default.aspx
http://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/default.aspx(英語 原文)
読み取りと書き込みは開始することができない。
Reads and writes cannot be introduced.
の意味がよくわからんなぁ・・・。

○その他
C#でのvolatile
読み取った値をキャッシュに置かないようにする
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpref/html/frlrfsystemreflectionemitopcodesclassvolatiletopic.asp

アウトオブオーダ実行やコンパイラの最適化の抑止
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/csspec/html/vclrfcsharpspec_10_4_3.asp

・Thread.MemoryBarrier
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpref/html/frlrfSystemThreadingThreadClassMemoryBarrierTopic.asp
「メモリを同期します。結果として、現在のスレッドを実行しているプロセッサで、キャッシュ メモリの内容がメイン メモリにフラッシュされます。」
3・CPUのキャッシュに値が載ってることがある
の対策になる。

「複数の Intel Itanium プロセッサを使用しているシステムなど、ウィーク メモリ オーダリングを採用したマルチプロセッサ システムでだけ使用します。」
ウィーク メモリ オーダリングがよくわからん。

・スピンロック
http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%94%E3%83%B3%E3%83%AD%E3%83%83%E3%82%AF

・深追い
Lock-freeとWait-freeアルゴリズム
http://ja.wikipedia.org/wiki/Lock-free%E3%81%A8Wait-free%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0

コンペア・アンド・スワップ
http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%9A%E3%82%A2%E3%83%BB%E3%82%A2%E3%83%B3%E3%83%89%E3%83%BB%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97
オプティミスティックロックっぽいかんじ。

ソフトウェアトランザクショナルメモリ
http://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%83%A1%E3%83%A2%E3%83%AA

C#でのソフトウェアトランザクショナルメモリ
さわったことはない
http://research.microsoft.com/research/downloads/Details/6cfc842d-1c16-4739-afaf-edb35f544384/Details.aspx

Cでのvolatile
http://mkosaki.blog46.fc2.com/blog-entry-91.html