174

誰かが次の違いを説明できますか:

  • ロック (someobject) {}
  • ミューテックスの使用
  • セマフォの使用
  • モニターの使用
  • その他の .Net 同期クラスの使用

私はそれを理解することはできません。最初の2つは同じように思えますか?

4

7 に答える 7

141

素晴らしい質問です。私は間違っているかもしれません..試してみましょう..私の元の答えのリビジョン#2..もう少し理解して。読んでくれてありがとう:)

lock(obj)

  • (オブジェクト内?)スレッド同期用のCLR構造です。1つのスレッドのみがオブジェクトのロックの所有権を取得し、ロックされたコードブロックに入ることができるようにします。他のスレッドは、現在の所有者がコードのブロックを終了してロックを放棄するまで待機する必要があります。また、クラスのプライベートメンバーオブジェクトをロックすることをお勧めします。

モニター

  • lock(obj)は、モニターを使用して内部的に実装されます。クリーンアップ手順を忘れるような間抜けを防ぐため、lock(obj)を使用することをお勧めします。必要に応じて、これは「ばかげた証拠」のMonitor構造です。
    モニターは.NETFramework専用に設計されているため、リソースをより有効に活用できるため、モニターの使用はミューテックスよりも一般的に好まれます。

ロックまたはモニターを使用すると、スレッドに依存するコードブロックが同時に実行されるのを防ぐのに役立ちますが、これらの構造では、あるスレッドが別のスレッドにイベントを通信することはできません。これには、同期イベントが必要です。同期イベントは、シグナル付きとシグナルなしの2つの状態のいずれかを持つオブジェクトであり、スレッドのアクティブ化と一時停止に使用できます。Mutex、SemaphoresはOSレベルの概念です。たとえば、名前付きミューテックスを使用すると、複数の(管理された)exe間で同期できます(アプリケーションの1つのインスタンスのみがマシンで実行されていることを確認してください)。

ミューテックス:

  • ただし、モニターとは異なり、ミューテックスを使用してプロセス間でスレッドを同期できます。プロセス間同期に使用される場合、ミューテックスは別のアプリケーションで使用されるため、名前付きミューテックスと呼ばれます。したがって、グローバル変数または静的変数を使用してミューテックスを共有することはできません。両方のアプリケーションが同じミューテックスオブジェクトにアクセスできるように、名前を付ける必要があります。対照的に、MutexクラスはWin32構造のラッパーです。モニターよりも強力ですが、ミューテックスには、Monitorクラスで必要とされるものよりも計算コストの高い相互運用遷移が必要です。

セマフォ(私の脳を傷つけます)。

  • Semaphoreクラスを使用して、リソースのプールへのアクセスを制御します。スレッドは、WaitHandleクラスから継承されたWaitOneメソッドを呼び出してセマフォに入り、Releaseメソッドを呼び出してセマフォを解放します。セマフォのカウントは、スレッドがセマフォに入るたびにデクリメントされ、スレッドがセマフォを解放するたびにインクリメントされます。カウントがゼロの場合、後続のリクエストは他のスレッドがセマフォを解放するまでブロックされます。すべてのスレッドがセマフォを解放すると、カウントはセマフォが作成されたときに指定された最大値になります。 スレッドはセマフォに複数回入ることができます。Semaphoreクラスは、WaitOneまたはReleaseでスレッドIDを強制しません。プログラマーはマックアップしない責任があります。 セマフォには、ローカルセマフォと名前付きセマフォの2種類があります。システムセマフォ。名前を受け入れるコンストラクターを使用してセマフォオブジェクトを作成すると、その名前のオペレーティングシステムセマフォに関連付けられます。名前付きシステムセマフォはオペレーティングシステム全体に表示され、プロセスのアクティビティを同期するために使用できます。 ローカルセマフォは、プロセス内にのみ存在します。これは、ローカルのセマフォオブジェクトへの参照を持つプロセス内の任意のスレッドで使用できます。各セマフォオブジェクトは、個別のローカルセマフォです。

読むページ-スレッド同期(C#)

于 2008-11-19T06:33:03.710 に答える
31

「他の.Net同期クラスの使用」について-知っておくべき他のいくつか:

  • ReaderWriterLock-複数のリーダーまたは単一のライターを許可します(同時にではありません)
  • ReaderWriterLockSlim-上記のように、オーバーヘッドを低くする
  • ManualResetEvent-開いたときにコードが通過できるようにするゲート
  • AutoResetEvent-上記と同じですが、開くと自動的に閉じます

CCR / TPL( Parallel Extensions CTP)にはさらに多くの(オーバーヘッドの少ない)ロック構造がありますが、IIRCでは、これらは.NET4.0で利用可能になります。

于 2008-11-19T06:58:09.057 に答える
15

ECMAで述べられているように、またReflectedメソッドからわかるように、lockステートメントは基本的に次のようになります。

object obj = x;
System.Threading.Monitor.Enter(obj);
try {
   …
}
finally {
   System.Threading.Monitor.Exit(obj);
}

前述の例から、モニターがオブジェクトをロックできることがわかります。

Mutexeは、文字列識別子をロックできるため、プロセス間同期が必要な場合に役立ちます。同じ文字列識別子を異なるプロセスで使用して、ロックを取得できます。

セマフォはステロイドのミューテックスのようなもので、同時アクセスの最大数を提供することで同時アクセスを可能にします。制限に達すると、呼び出し元の1人がセマフォを解放するまで、セマフォはリソースへのそれ以上のアクセスをブロックし始めます。

于 2008-11-19T06:40:29.560 に答える
14

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

于 2012-06-06T16:36:51.570 に答える
9

文字列 ID で識別した共有ミューテックスをロックする場合の追加の注意事項は、デフォルトで "Local\" ミューテックスになり、ターミナル サーバー環境のセッション間で共有されないことです。

共有システム リソースへのアクセスが適切に制御されるように、文字列識別子の前に "Global\" を付けます。これに気付く前に、システムアカウントで実行されているサービスとの通信を同期する際に、山ほどの問題に遭遇していました。

于 2009-04-06T03:41:51.297 に答える
5

可能であれば、「lock()」、「Mutex」、「Monitor」は避けようと思います。

.NET4の新しい名前空間System.Collections.Concurrentを確認してください。
スレッドセーフなコレクションクラスがいくつかあります。

http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx

ConcurrentDictionaryロック!もう手動でロックする必要はありません!

于 2010-05-18T12:05:27.833 に答える