誰かが以下の違いを説明できますか?
わかりません。私には最初の2つは同じようですか?
いい質問ですね。私は間違っているかもしれません..試してみましょう..私のオリジナルの回答のリビジョン#..少し理解を深めてください。読んでくれてありがとう:)
lock(obj)
Monitors
ロックまたはモニターの使用は、スレッドの影響を受けやすいコードブロックの同時実行を防ぐのに役立ちますが、これらの構造では、あるスレッドが別のスレッドとイベントをやり取りすることはできません。これには、同期イベントが必要です。これは、スレッドのアクティブ化と一時停止に使用できる、シグナル状態と非シグナル状態の2つの状態のいずれかを持つオブジェクトです。ミューテックス、セマフォはOSレベルの概念です。たとえば、名前付きミューテックスを使用すると、複数の(管理された)exe間で同期できます(アプリケーションの1つのインスタンスのみがマシンで実行されていることを確認します)。
Mutex:
セマフォ(私の脳を傷つけます)。
「他の.Net同期クラスの使用」について-知っておく必要のある他のいくつか:
CCR/TPL( Parallel Extensions CTP)にはさらに多くの(低オーバーヘッド)ロック構造もありますが、IIRC、これらは.NET 4.0で利用可能になります
ECMAで述べられているように、またReflectedメソッドからわかるように、lockステートメントは基本的に次と同等です。
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
…
}
finally {
System.Threading.Monitor.Exit(obj);
}
前述の例から、モニターはオブジェクトをロックできることがわかります。
ミューテックスは、プロセス間同期が必要なときに便利ですcan文字列識別子をロックします。同じ文字列識別子を異なるプロセスで使用して、ロックを取得できます。
セマフォはステロイドのミューテックスに似ており、同時アクセスの最大数を提供することで同時アクセスを許可します。制限に達すると、呼び出し元の1人がセマフォを解放するまで、セマフォはリソースへのそれ以上のアクセスのブロックを開始します。
DotGNUでスレッド化のクラスとCLRをサポートしましたが、いくつかの考えがあります...
プロセスにまたがるロックを必要としない限り、ミューテックスとセマフォの使用は常に避けてください。 .NETのこれらのクラスは、Win32 MutexおよびSemaphoresのラッパーであり、かなり重いです(特に、ロックが競合していない場合は、カーネルへのコンテキストスイッチが必要です)。
他にも言及されているように、C#lockステートメントはMonitor.EnterおよびMonitor.Exitのコンパイラーマジックです(try/finally内に存在します)。
モニターには、Monitor.Pulse/Monitor.Waitメソッドを介したミューテックスにはないシンプルで強力な信号/待機メカニズムがあります。 Win32に相当するのは、CreateEventを介したイベントオブジェクトで、実際には.NETにもWaitHandlesとして存在します。 Pulse/Waitモデルは、Unixのpthread_signalおよびpthread_waitに似ていますが、競合しない場合は完全にユーザーモード操作にできるため、高速です。
Monitor.Pulse/Waitは簡単に使用できます。 1つのスレッドで、オブジェクトをロックし、フラグ/状態/プロパティをチェックします。それが予期したものでない場合は、Monitor.Waitを呼び出してロックを解除し、Pulseが送信されるまで待機します。待機が戻ると、ループバックしてフラグ/状態/プロパティを再度チェックします。もう1つのスレッドでは、フラグ/状態/プロパティを変更するたびにオブジェクトをロックし、PulseAllを呼び出してリスニングスレッドを起動します。
多くの場合、クラスをスレッドセーフにして、コードにロックを設定します。ただし、多くの場合、クラスは1つのスレッドでのみ使用されます。これは、ロックによってコードが不必要に遅くなることを意味します...これは、CLRの巧妙な最適化がパフォーマンスの向上に役立つ場所です。
Microsoftのロックの実装についてはわかりませんが、DotGNUとMonoでは、ロック状態フラグがすべてのオブジェクトのヘッダーに保存されます。 .NET(およびJava)のすべてのオブジェクトはロックになる可能性があるため、すべてのオブジェクトはヘッダーでこれをサポートする必要があります。 DotGNU実装には、ロックとして使用されるすべてのオブジェクトに対してグローバルハッシュテーブルを使用できるフラグがあります。これには、すべてのオブジェクトの4バイトのオーバーヘッドを排除できるという利点があります。これはメモリ(特にスレッドが多くない組み込みシステム)には適していませんが、パフォーマンスに影響があります。
MonoとDotGNUの両方は、ミューテックスを効果的に使用してロック/待機を実行しますが、スピンロックスタイル compare-and-exchange 操作を使用して、本当に必要でない限り、実際にハードロックを実行する必要性を排除します:
ここでモニターを実装する方法の例を見ることができます:
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
文字列IDで識別した共有Mutexのロックに関する追加の注意点は、デフォルトで「Local \」ミューテックスになり、ターミナルサーバー環境のセッション間で共有されないことです。
文字列識別子の前に「Global \」を付けて、共有システムリソースへのアクセスが適切に制御されるようにします。これに気付く前に、SYSTEMアカウントで実行されているサービスと通信を同期する際に問題が山積していました。
可能な場合は、「lock()」、「Mutex」、「Monitor」を避けるようにします...
.NET 4の新しい名前空間System.Collections.Concurrentをご覧ください
いくつかのニーススレッドセーフコレクションクラスがあります
http://msdn.Microsoft.com/en-us/library/system.collections.concurrent.aspx
ConcurrentDictionaryロック!もう手動でロックする必要はありません!