C#のマルチスレッド・ロックシステム(B)プログラミング
最後の章では、彼が直接ロックを行使用方法については、主です。しかし、それらの現実すべてのロックと、あまりにも無駄な、または排他ロックの粒度は大きすぎます。今回はロックとアトミック操作のアップグレードについて話しています。
内容量
1:揮発性
2:インターロック
3:ReaderWriterLockSlim
4:要約
A:揮発性
簡単に言えば:volatileキーワードは、C#コンパイラとJITコンパイラに指示し、任意の揮発性のフィールドは、キャッシュをマークしません。読み取りおよび書き込み操作は、フィールド、最新の値を確認してくださいアトミックです。
その上にロックすることをではないですか?このストックは、その動作は、原子CPU自体、非ブロックに基づいており、それがロックされていることではありません。CPU 32は、割当指示、4バイトのデータ送信最大幅からです。
読み取りおよび4バイト以下で書き込み操作限り、32ビットCPUはアトミックです。揮発性それが来て、この機能を使用することです。
グッド残酷な真実?そうでない場合は、マイクロソフト大法いくつかのデータは、(マルチスレッド)キャッシュのJITの性能効率を向上させるためになります。
//正しい
公共のInt32 SCORE1 =揮発1;
//与えられた
パブリック揮発性のInt64 score2 = 1。
私たちは死ぬscore2 8バイトの長さを定義し、上記の例を参照してください。8つのバイトので、CPU32は、実行2つの命令に分割されています。当然のことながら、我々は原子動作を保証することはできません。
このような詳細は、実行する方法を忘れてしまった、それはそのKengrenああを意味します。だから、マイクロソフト大法は直接、具体的にそれをMSDN何を参照するために、揮発性の低いを使用するために、4バイトのタイプフィールドを制限し、死に彼を倒します。
さて、今日は私が知っています。私は64 CPUで、64ビットプラットフォーム、唯一の揮発性のint64に大丈夫コンパイル?いいえ、コンパイラエラー。手厳しいを言いました。。
(^ ._。^)テクノまあ、実際には、あなたがこののIntPtrを使用することができます。
ほとんどの場合、揮発性の非常に便利なの下では、結局、ロックのパフォーマンス・オーバーヘッドは依然として非常に大きいです。私たちは、軽量ロックとして、シーン合理的な用途に応じて、プログラムのパフォーマンスの多くを向上させることができます。
スレッドThread.VolatileRead Thread.VolatileWriteは複雑での揮発性のバージョンです。
二:インターロック
MSDN説明:アトミック操作では、複数のスレッドで共有変数を提供します。次のように主な機能は次のとおりです。
Interlocked.Incrementアトミック操作、増分値格納指定された変数の結果。
Interlocked.Decrementアトミック操作、および格納する結果値は、指定された変数をデクリメントします。
アトミック操作をInterlocked.Add、そして最初の整数の両方で2つの整数を加算して置き換えます
Interlocked.CompareExchangeは(A、B、C REF);比較アトミックオペレーション、パラメータAと、パラメータcは置換aがbと等しい、等しくないが置き換えられません。
基本的な使い方は言っているわけではありません。C#のインターロックは何も例を経由して直接CLRセグメント:
最大静INTパブリック(REF対象のint、int値)
{
INT = currentValターゲット、StartVal、desiredVal;前後//レコード値
DO
{
StartVal = currentVal; //は反復ループの初期値を記録します。
desiredVal = Math.Max(startVal、値) ; // 値と期待値がStartVal desiredValに基づいて算出されます
高い同時実行の下で、スレッドが状況下で先取りされている//、目標値が変更されます。
//ターゲットstartVal同じ番組変更なし。desiredVal直接交換。
currentVal = Interlocked.CompareExchange(REFターゲット、desiredVal 、startVal)。
}一方(startVal = currentVal!) ; // 等しくない命令は、目標値が他のスレッドによって変更されています。スピンを続けます。
返すdesiredVal;
}
三:ReaderWriterLockSlim
私たちは、キャッシュされたデータAをとっている場合に関係なく、任意のアクションのたびにそれをロックした場合、その後、私は今まで並行性の高いウェブの下に耐え難いある、読み書きするシングルスレッドこのキャッシュすることができます。
私が書くとき、それはそれを読むためにスレッド数を制限しません排他ロックをのみ入力することができます方法はありますか?その答えは、私たちの主人公ReaderWriterLockSlim、読み書きロックということです。
最もEnterUpgradeableReadLock ReaderWriterLockSlimの一つは、キーロックをアップグレードすることができますロック。
それは、あなたがロックに入ることを可能にすると、Aは同じではありませんキャッシュを見つけ、その後、書き込みロックを入力して、読み取りロックモードを書いた後戻りました。
PS:ネットはReaderWriterLock 3.5前にパフォーマンスの低下を持っていることをここで注意してください。ReaderWriterLockSlimのアップグレード版を使用することをお勧めします。
読み書きロック//の例
ReaderWriterLockSlim cacheLock =新しいReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion) 。
ここで、上記の例読み書きロックは、コンストラクタの列挙ことに留意す。
再帰をサポートしていませLockRecursionPolicy.NoRecursion例外をスローすることが判明します。
再帰的なパターンをサポートすることですLockRecursionPolicy.SupportsRecursionは、スレッドロックは、ロックを使用し続けています。
cacheLock.EnterReadLock();
//
cacheLock.EnterReadLock();
//
cacheLock.ExitReadLock();
cacheLock.ExitReadLock();
このモデルは、簡単に簡単に、このようなロックを使用して読み書きロックとして、デッドロックすることができます。
cacheLock.EnterReadLock();
//
cacheLock.EnterWriteLock();
//
cacheLock.ExitWriteLock();
cacheLock.ExitReadLock();
ここでキャッシュMSDNの例の直接保持され、簡単なコメントを追加します。
パブリッククラスSynchronizedCache
{
プライベートReaderWriterLockSlim cacheLock =新しいReaderWriterLockSlim();
プライベート辞書<int型、文字列> innerCache =新しい辞書<int型、文字列>();
読み取りストリングpublic(int型キー)
{
//ロックに読み込ま、他のすべてのスレッドが読み込み可能、スレッドの書き込みがブロックされています。
cacheLock.EnterReadLock();
試みは、
{
[キー] innerCacheを返す;
}
最後に
{
cacheLock.ExitReadLock();
}
}
パブリック(int型のキー、文字列値)を追加無効
{
//ロックに書き込み、他のすべてのスレッド・アクセス操作はブロックされます。その排他的な書き込みロック。
cacheLock.EnterWriteLock();
試み
{
innerCache.Add(キー、値);
}
最後に
{
cacheLock.ExitWriteLock();
}
}
BOOL AddWithTimeoutパブリック(int型のキー、文字列値、int型のタイムアウト)
{
//設定されたタイムアウト、タイムアウト期間内に、他の書き込みロックが解除されていない場合は、操作をあきらめます。
IF(cacheLock.TryEnterWriteLock(タイムアウト))
{
試み
{
innerCache.Add(キー、値);
}
最後に
{
cacheLock.ExitWriteLock();
}
trueに復帰;
}
他
{
falseに復帰;
}
}
AddOrUpdateStatus AddOrUpdateパブリック(int型のキー、文字列値)
{
//ロックに更新。1つのスレッドしかアップグレードをロックすることができます。ロックを書いて、ロックのアップグレードがブロックされているが、他のスレッドがデータを読み取ることができます。
cacheLock.EnterUpgradeableReadLock();
試み
{
文字列の結果= NULL;
IF(innerCache.TryGetValue(キー、OUT結果))
{
(結果==値)のIF
{
AddOrUpdateStatus.Unchangedを返す;
}
他
{
//書き込みロックへの更新、他のすべてのスレッドがブロックされています。
cacheLock.EnterWriteLock();
トライ
{
innerCache [キー] =値;
}
最後に
{
//出口書き込みロック、他のスレッドが読み取ることを可能にします。
cacheLock.ExitWriteLock();
}
AddOrUpdateStatus.Updatedを返す;
}
}
他
{
cacheLock.EnterWriteLock();
試み
{
innerCache.Add(キー、値);
}
最後に
{
cacheLock.ExitWriteLock()。
}
戻りAddOrUpdateStatus.Added。
}
}
最後に
{
//退出升级锁。
cacheLock.ExitUpgradeableReadLock();
}
}
パブリック列挙AddOrUpdateStatus
{
を追加し、
更新、
変更なし
}。
}
4:要約
マルチスレッドは、実際の開発では、テストは、多くの場合は問題は、本番環境に、高い同時実行が、間違って行くことは容易ではありません、我々は注意を払う必要があります。
C#の経由リファレンスここCLR。