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