スレッドロック
使用シナリオ:共有リソースへの同期スレッドへのアクセスは、(あなたが結果を計算して、あなたのオブジェクトの割り当てにロックできるように、時にはとして、少なくともリソースをロックしようとします)
スレッドの優先度:[キュー] - > [レディキュー] - >スレッドロック[あり]
特性のロックを:
- 唯一のあなたは、コンテンツの一貫性を確保するために、データを共有することができるように一つのスレッドは、特定のロックを保持できるように相互排他手段;
- 可視性は、別のスレッドがロックに続いてロックが解除される前に、共有データへの変更は、行動を知ることができることを保証する必要性を指します。
.NET複数のカプセル化System.Threading.WaitHandleクラスから派生した同期プリミティブのネイティブ・オペレーティング・システムは、同期処理スレッドの相互作用およびシグナル伝達機構を。
同期の軽量タイプは、一般的に優れたパフォーマンスを提供し、基礎となるオペレーティングシステムハンドルには依存しません。しかし、彼らは、プロセス間の同期に使用することはできません。これらのタイプは、一つのアプリケーションのスレッド同期に使用されています。
これらのタイプのいくつかは、代替案のWaitHandle型から派生しています。例えば、軽量の選択肢のSemaphoreSlimセマフォ。
mutexロック
- 最も一般的に通常の状況下で、使用がロックを使用することを推奨し、排他的アクセスを提供するための好ましい方法であります
- 好ましくは、ロックは、代わりに関連付けられたコードの値型または他の種類の必要な充填物の種類の値から、読み出し専用タイプ固有の基準となる
文字列、typeof演算、(それが新しいもよい別れ公共の場所)本の使用を避けます(同じアドレス文字列は、その基準とすることができます)。 - ランダムは、RAD =新しいランダム()は、ロック(RAD)これはあなた自身であるに予測します
- ロックは、スレッドロック2スレッドを有するロック用B B Aロックを有し、デッドロックが発生する可能性があります。
モニタのミューテックス
- ロックは、最終的に{Monitor.Exitは}ロックを対応{Monitor.Enter}を試すそのパッケージであります
- モニターの違いはfalseを返すために失敗したロックを取得しようとすると、tryEnterがあるということです。
- モニターの違いがあり、待っパルスとPulseAll方法、タイムアウトメカニズムがあるということです
1.Monitor.Waitメソッド
スレッドの呼び出しを待って、それが取得ロックに待ちキュー、レディキューオブジェクトの次のスレッド(もしあれば)にオブジェクトとオブジェクトのロックを解除し、オブジェクトを排他的に使用されています。あなたが再びロックを使用する権利を取得するまで待ちますが()ロックを使用する権利の上に手に、スレッドがブロックされています。
2.Monitor.Pulse方法
キュー内の次のスレッドをロックする信号を送信するために、現在のスレッド呼び出し、この方法。パルスを受信した後、待機しているスレッドは、レディキューに移動されます。ロックスレッドリリースを呼び出した後、レディキュー(必ずしも受信スレッドパルス)の次のスレッドがロックを取得するパルス。パルスは、()現在のスレッドがロックを解除することはありません。
スレッドは、スレッドがレディキューにキューイングされたときに同期オブジェクトをロックしようとすると。誰も同期オブジェクトを所有していないならば、レディキューのスレッドが同期オブジェクトを占めることができます。これは、我々は通常、最も頻繁に使用されるロック方法です。他の同期目的のために、スレッド同期オブジェクトの所有が一時的に同期オブジェクトを放棄して行くためにキュー内で待機するように自分自身を追放することができ、これはMonitor.Waitであり、スレッド同期オブジェクトを放棄するので、他のラインアップキュー内に準備ができて私たちは、その後、同期オブジェクトを持つことができます。レディキューと比較すると、キューのスレッドで待機中のキューは、複数の第二級市民のようなものです:彼らは自動的に同期オブジェクト、レディキューにいなくても自動アップグレードを得ることはありません。Monitor.Pulseの役割は、ドアを開けたスレッドのキューがレディキューへのアップグレードを待っているようにすることです。ドアを開けMonitor.PulseAll対応するレディキューにキュー内で待機中のすべてのスレッドを置きます。
スピンロックスピンミューテックス
- また特定のシナリオのためのモニターは、モニターより隠されたため、オブジェクトの割り当て、ガベージコレクションの圧力アレクサンダー、スピンロックスピン待ちが含まれているが、それは単にスピン待ちのパッケージとして理解されていません
- 使用条件:短い待ち時間とパフォーマンスが改善されるかどうかをテストするには、プロジェクトのニーズを競合の非常にまれなケースを使用し、l_spinlock.enter(REF l_islock)。
- スピンロックは、読み取り専用フィールドとして宣言しないでください、読み取り専用フィールドとして宣言された場合、各呼び出しがマルチスレッドで、新しいコピースピンロックを返しますつながる、各メソッドをロックすることは成功しますが、クリティカル領域に従って保護されることはありませんこれは、シリアル化すると予想しました。
連動アトミック操作は、変数が複数のスレッドによって共有される提供します
- インクリメントデクリメントする減算値増分が長く、int32の減少、ダブル
- データ交換のために、それは数字に限定されるものではなく、
EG:取引所(T、T)またはExchange(オブジェクト、オブジェクト)アトミック操作の前回値と元の値に割り当てられた値による。
int a = 1;
Console.WriteLine(Interlocked.Exchange(ref a,2));
Console.WriteLine(a);
Console.ReadKey();
// 输出结果为:1 2
string aa = "abc";
Console.WriteLine(Interlocked.Exchange(ref aa,"bb"));
Console.WriteLine(aa);
//输出结果为 abc bb
- 比較
CompareExchangeを交換が第2の値を有する第1の値に等しい場合は第3の値と最初の値とを比較する(T、T、T REF)、等しく、
元の値
int cc = 1;
Console.WriteLine(Interlocked.CompareExchange(ref cc, 2,1));
Console.WriteLine(cc);
//输出 1 ,2
EventWaitHandle
- MaualResetEventロック手動リセットメソッドが呼び出されるまで、信号が発行された信号が残るとき
- AutoResetEventは、単一の待ち状態信号がスレッドに発行されていない後の信号は、リリースが自動的にリセットされますときに、自動的にロック
セマフォSemaphoreSilm信号量锁
スレッドの数を制限し、同時に共有リソースまたはリソースプールにアクセスし、セマフォのカウント、セマフォは、ステータス信号を設定しますが発行されたとき、ゼロより大きく、ゼロセマフォのカウントは、セマフォのステータスを設定しないとき信号。
残留量が1より大きい場合WAITONE待機信号を使用することができ、その後、コードはWAITONE背後続け、
WAITONE(10ms)の残量をより1を使用することができる以上である場合、次いで、次の待機10msのこの消費時間信号を続行量、何セマフォが消費できない、
残りの使用可能量が1より大きい場合、無料のを待つが、セマフォを消費する必要があります。
リリース()セマフォ解除=(1)を放出し、
放出(INT releaseCount)時間放出セマフォ複数の、それが最大許容信号にレリーズ信号後の総量である場合ますが例外
try { //最大数是4,却释放了2个,这个时候剩余信号量为3+2 = 5大于4 所以异常 Semaphore semaphore = new Semaphore(4, 4, "wp"); semaphore.WaitOne(); semaphore.Release(2); } catch (SemaphoreFullException ex1) { Console.WriteLine(ex1); throw; }
volatile変数修飾子
キャッシュメモリから読み出さのではなく、同時に一つのスレッドだけのアクセスで修正変数とそれを避けます
交換用のThread.sleep(0)のためのスピン待ちスピン待ち。
条件:あなたは、特に短期、世界のニーズを満たすための条件を待って、高価なコンテキストスイッチが発生したくない場合は、長いスピンは良い習慣ではない、スピンは、より高度なスレッドと関連するタスクをブロックしますので、これは、ガベージコレクションをブロックすることができます。
スピンウェイト各タスクまたはスレッドが自分のスピンウェイト例を使用する必要があり、複数のタスク又はスレッドがスピンウェイト法により、同時にので、複数のタスク又はスレッドスピンを使用できるように設計されていない、
ソースコードでスピンウェイトが一定回数を超えていますそれを、のThread.sleep(0)を呼び出すことが可能であるのThread.sleep(1 ) が優先順位の逆転場合、望ましくない高価なコンテキストスイッチであるが、また、コンテキストスイッチが発生するかどうか。
、;スピン待ちコアパーティは、私たちがマルチコアCPUであれば、前者の方法はNextSpinWillYield [10] [SpinOnceコールThread.SpinWaitこれは、Win32の方法、プライベート静的にextern無効SpinWaitInternal(int型の反復)である]偽である、SpinOnce方法であります主コールはThread.Yield()を呼び出すことである背後【のWin32API、プライベート静的にextern BOOL YieldInternal()]、カウントが29最初の呼のThread.sleep(0)であるとき場合カウントが14である場合に最初の呼び出しThread.sleep(1)、ルール後(COUNT-10)%20回の== 19コールのThread.sleep(1)、チェック(カウント-10)%5 == 4Thread.Sleep(0)によってか。
条件は、ループを終了するには会ったか、タイムアウトしている場合には実現文SpinUntil方法は、サイクル呼び出しSpinOnce方法であること、非常に簡単です。
違い:
Thread.Yeild
この新しいメソッドは、基本となるメソッドに対応する.NET 4.0で導入されたことSwitchToThreadです。中国の収量は「あきらめ」ここで、現在のスレッドのタイムスライスを放棄し、タイムスライスを使用して、オペレーティング・システムのスレッドスケジューリング、他の状態が準備できるようにする取り組みを意味して翻訳しました。しかし、あなたは代わりにキューをブロックする、レディキューにちょうど現在のスレッド、収量を呼び出す場合。他のスレッド実行可能状態が見つからない場合は、現在のスレッドが実行を継続します。
利点:より高速のThread.sleep(0)の速度よりも、現在の優先度のスレッドよりも低いが、実行することを可能にします。戻り値は、他のスレッドの成功かどうかを判断するためにスケジュールすることができます。
短所:唯一のプロセッサとのスレッドをスケジュールすることができるが、他のプロセッサは、スレッドをディスパッチすることができません。ときに他の準備のスレッドは、常に100%のCPU使用率で、その結果、CPUのタイムスライスを取るんだろうThread.sleep(0)
スリープ時は休むように、Nミリ秒が、今回はそれを別の準備のスレッドを与えるために、独自のオペレーティングシステムを伝えることを意味します。とき= 0の意味は、その残りのタイムスライスを放棄することであるnは、まだ準備ができて、実際には、多少同様の意味と収量。しかし、スリープ(0)は、他のスレッドのみ空腹待つことができ、現在のCPUと等しいかまたはより高い優先度のスレッドのみを可能にします。いいえ、適切なスレッド場合は、現在のスレッドのCPU時間のスライスを再使用します。
長所:収量を比較すると、スレッドは、任意のプロセッサのタイムスライスをスケジュールすることができます。
短所は:のみ、優先順位の低いスレッドがタイムスライスを取得することは困難であることを意味同等以上の優先度のスレッドをスケジュールすることができ、それが何かを呼び出すことはありませんがあります。ときに適格なスレッドが常に100%の稼働率のCPUで、その結果、CPUのタイムスライスを負いません。Thread.sleep(1)
このメソッドは、タイムスライスの残りの部分を放棄するために、現在のスレッドを強制的にパラメータとして1を使用し、1ミリ秒休ま(それはリアルタイムオペレーティングシステムではないため、時間が正確に保証することはできません、一般的に数ミリ秒の時間を遅らせること錠)。しかし、このような利点は、他のすべてのスレッドがレディ状態のタイムスライスで競争する機会を持っているし、優先順位を気にしないということです。
利点:あなたは任意のプロセッサのタイムスライスのスレッドをスケジュールすることができます。満たしていないスレッドがあるかどうか、CPU時間を放棄するため、低CPU使用率ます。
短所:スピードが遅くなるので、少なくとも、いくつかの時間を休まますので、のThread.sleep(0)を比較します。
バリアバリア
あなたが並行して段階、各段階のシリーズを実行しているタスクのセットを必要とするが、他のすべてのタスクは、前の段階を完了した後に起動するのを待つ必要がある場合、あなたは一例による障壁のこのタイプを同期させるために一緒に働きます。
バリアは、初期化した後、信号到着の特定の番号の待機が、障壁の数は、このアクションは、また、バリア初期化時に指定され、バリアが指定されたアクションを実行し、指定された信号の数が来ている、初期化時に指定しました。アクションの実装後の障壁は、その後、信号の一定数の到着を待ち、その後、指定されたアクションを実行するために回し、リセットされます。信号()メンバ関数は、実行SignalAndWait()タスク関数の入力またはスレッドは、待機するバリア信号の一定量待ちが到着し、指定操作バリアリセット後、次いでSignalAndWait()関数を実行SignalAndWaitによって送信されますまたはどこタスクスレッドが実行し続けます。プログラムの動作中に、メンバ関数AddParticipant()とRemoveParticpant(増加)または待機する信号の数を減らすことができます
CountdownEvent一般的に使用されていません
CountDownEventメンバ関数は、信号()の呼び出しは、特定の回数のためであるメンバ関数までブロックします()待ちと呼ばれ、その後CountDownEventは、()関数は、もはやブロックされるまで待機を呼び出し、レディ状態にCountDownEventのために、準備状態と呼ばれます手動での関数呼び出しの後にリセット()が呼び出されるまで待ちます()関数は再びブロックされます。CountDownEvent缶()関数は、TryAddCount()とAddCountによって(と呼ばれる番号が必要)機能シグナルを増大させるために、しかし、ときにのみCountDownEvent、準備ができていない状態成功するために。それ以外の場合は、関数が呼び出されるに応じて、可能性の例外をスローします
、到達した時点を同期するタスクがあるとき、関数はその数を減らすために信号と呼ばれるAddCountはその数を増やす呼び出す、生成するタスクを同期するための新しい必要がある場合、 CountdownEventカウントがゼロであるとき、それはすべてのタスクが同期させる必要があることを意味が完了している、あなたは、次のタスクを開始することができます。
ReaderWriterLock ReaderWriterLockSlim
- 複数のスレッドを読むことを可能にし、排他的な書き込み(書き込みモードで任意の時間に1つのだけのスレッド、スレッドが書き込みモードにあるとき、他のスレッドは、どのモードでロックされた状態に入ることができます)
- そして、スケーラブルな読み取りモードは、このモードでは、スレッドがリソースへの読み取りアクセスを放棄することなく、書き込みモードにアップグレードすることができますことができます。いつでも、スレッドで唯一のスレッドが読み取りアクセス権を持っていますアップグレードモードインチ これは、読み取りモードで任意の数のスレッドにすることができ、読み取りモードでは、他のスレッド、スレッドは1つのスケーラブルなモードであるとき、
ReaderWriterLockSlim類似ReaderWriterLockが、しかし、違いは、前者を簡素化再帰ルール、およびアップグレードおよびダウングレードロック状態規則。ReaderWriterLockSlimは、多くの潜在的なデッドロック状況を回避します。さらに、ReaderWriterLockSlimのパフォーマンスが有意に良好ReaderWriterLockを超えました。ReaderWriterLockSlimは、すべての新規開発プロジェクトのために推奨されます。
プロセス・ロック
.NET Frameworkでは、原因WaitHandleがSystem.MarshalByRefObjectから派生し、
そのため、これらのタイプは、アプリケーションドメインの境界のスレッド同期の活動にまたがって使用することができます。
オペレーティングシステムは、プロセス間の同期のために使用することができるを通じていくつかのタイプは、システム同期ハンドル名前表すことができ、ここで、.NET Frameworkと.NETコアにおいて、これらのハンドルが表示されています。
Mutex(.NET Framework 和 .NET Core)、
Semaphore(.NET Framework 和 Windows 上的 .NET Core)、
EventWaitHandle(.NET Framework 和 Windows 上的 .NET Core)。
クロスプロセスミューテックスのロックは、もちろん、また、スレッド同期プロセスで達成することができるが、消費より多くのリソースは、Win32のパッケージがされ
、共有リソースへの排他的アクセスを許可されました。それは任意のスレッドによって所有されていない場合、mutexはすでに状態を通知します- セマフォ
セマフォ二つのタイプに分け:ローカルセマフォと名前のセマフォシステム
//多个进程之间用相同的名称;
Semaphore semaphore = new Semaphore(4, 4, "wp");
semaphore.WaitOne();
semaphore.Release();
//第一个控制台应用程序里面写
static void Main(string[] args)
{
Semaphore semaphore = new Semaphore(3, 3, "wp");
int times = 0;
while (true)
{
semaphore.WaitOne();
Console.WriteLine($"我第{ ++times}次告诉你我不喜欢你");
}
Console.ReadKey();
}
//第二个里面写,运行第一个项目后,在第二个项目输入a 并回车 那么第一个程序就会进行一次;
if (Semaphore.TryOpenExisting("wp", out Semaphore result1))
{
Console.WriteLine("wp 已经被别的进程占用");
while (true)
{
if (Console.ReadLine() == "a")
result1.Release();
}
}
- EventWaitHandle
その他の関連する概念:
- オブジェクトのロックは、通常、重要なゾーンと呼ばれ、アクセスが制限された機能ブロックを提供します