web-dev-qa-db-ja.com

「lock(typeof(MyType))」が問題になるのはなぜですか?

MSDNは、C#のlockキーワードについて次の警告を出します。

一般に、パブリック型、またはコードの制御が及ばないインスタンスをロックすることは避けてください。一般的な構成要素lock(this)、lock(typeof(MyType))、およびlock( "myLock")は、このガイドラインに違反しています。

* lock (this) is a problem if the instance can be accessed publicly.
* lock (typeof (MyType)) is a problem if MyType is publicly accessible.

それでも、それはそれに対する確固たる理由を与えません。ロック(これ)は説明されています ここではSO 。 lock(typeof(MyType))の場合に興味があります。それについて何が危険ですか?

ありがとうございました。

45
Alex K

何でもそのロックを取得できるため、デッドロック状態を防ぐことは困難または不可能であるため、危険です。

これに関する記事(「タイプオブジェクトをロックしないでください!」、Dr。GUIの記事)があり、RicoMarianiによるコメントがいくつかありました。どうやらこの記事は直接入手できなくなったようですが、 http://bytes.com/topic/c-sharp/answers/249277-dont-lockを含む「ミラー」が浮かんでいます。 -type-objects

抜粋は次のとおりです。

ここでの基本的な問題は、typeオブジェクトを所有しておらず、他に誰がアクセスできるかわからないことです。一般に、作成していないオブジェクトのロックに依存し、他に誰がアクセスしているのかわからないというのは非常に悪い考えです。そうすることはデッドロックを招きます。最も安全な方法は、プライベートオブジェクトのみをロックすることです。

ちょっと待って;それはそれよりもさらに悪いです。実は、現在のバージョンの.NETランタイムでは、型オブジェクトがアプリケーションドメイン間で共有されることがあります(プロセス間では共有されません)。 (これは不変であるため、通常は問題ありません。)つまり、別のアプリケーションドメインで(ただし同じプロセスで)実行されている別のアプリケーションが、ロックする型オブジェクトのロックを取得することで、アプリケーションをデッドロックする可能性があります。そして決してそれを解放しません。また、オブジェクトには名前(型の完全修飾名)があるため、その型オブジェクトに簡単にアクセスできます。ロックを取得できるようになるまで、lock/SyncLockがブロックすることを忘れないでください(これはハングの丁寧な言葉です)。別のプログラムまたはコンポーネントがロックしてデッドロックを引き起こす可能性のあるロックに依存することは、明らかに非常に悪いことです。

62
Michael Burr

これはlock(this)の場合と同じ問題です。他のコードがアクセスできる参照をロックしているため、その参照もロックされている可能性があります。

相互に除外するために意図的なしで同じ参照にロックしている2つの無関係なコードがある場合、最良の場合、並行性の欠如のためにパフォーマンスが少し低下する可能性があります-最悪の場合デッドロックが発生する可能性がある場合。

28
Jon Skeet

typeof (MyType)(タイプTypeのオブジェクト)の結果は広くアクセス可能であり、他のスレッドが同じオブジェクトをロックし、そのロックを無期限に保持できるためです。次に、MyTypeの内部ロジックは、同期ロジックに対する重要な制御を効果的に提供します。これが意図されている場合、これは実際の問題ではないかもしれませんが、防御的/懐疑的にコーディングすることはあなたの手口でなければなりません。

2
G-Wiz

ロックのターゲットは、他のスレッドが参照できるように、ロックブール値(ロックされているかどうか)を格納する場所を確立することだけであるためです。

ロックのターゲットが実際に何らかの形でロックされているという一般的な誤解は間違っています...「ロック」されているのは、....安全でない方法で共有メモリにアクセスできるメソッドでない限り、何もありません。このロックを確認し、解放されるまで続行しないコード... Typeオブジェクトを使用します。これは、ソリューションプロセススペース全体の任意の場所のコードスニペットがそのTypeオブジェクトにアクセスして、同期ブロックを変更できるため、ロックターゲットが間違っているためです。ロックブール値はに格納されます。ローカルスコープのオブジェクトを作成すると、「リスクのある」共有メモリにアクセスまたは混乱する可能性のあるスレッドとメソッドのみがロックにアクセスおよび/または変更できるようにすることができます。

0
Charles Bretana

この修正された並列形式のアドバイスに従った場合、これは「問題」にはなりません。

一般に、パブリック型またはインスタンス作成または定義していないをロックすることは避けてください。一般的な構造lock (this)lock (typeof (MyType))は、このガイドラインインスタンスを作成していないか、型を宣言していない場合に違反しています。

ただし、検出されたすべてのコードでパブリックタイプまたはアクセス可能なインスタンスに対して上記の「保証はできない」ため、MSDNおよびその他のソースは、これらはDefensive Programmingに対して、単一の可能性に対して回避する必要があると主張しています。 -ランタイム(デッドロック)の問題を検出する。ほとんどのコーダーがルールについてあまり上手でも勤勉でもないことを考えると、これは良いアドバイスです。

..そして、野生でそのようなバグに遭遇した人は、述べられたガイドラインを課すことによって、この特定の問題が再び発生することを可能にするnotについてはるかに固執するでしょう。 (スレッド化されたAWTUIモデルを備えたJava1.0/1.1は特に問題がありました。)

lock ("mylock")のケースは、上記のアドバイスに違反しているかどうかを一般に「知る」ことができないため、文字列のインターンのためにshould回避するという点で非常に特殊です。

0
user2864740

また、トピック「マネージドスレッドのベストプラクティス」の下にドキュメントも記載されています。 https://msdn.Microsoft.com/en-us/library/1c9txz50(v = vs.110).aspx

それは言う;

タイプをロックオブジェクトとして使用しないでください。つまり、C#のlock(typeof(X))やVisual BasicのSyncLock(GetType(X))などのコード、またはTypeオブジェクトでのMonitor.Enterの使用は避けてください。 特定のタイプに対して、アプリケーションドメインごとにSystem.Typeのインスタンスは1つだけです。ロックを取得するタイプがパブリックである場合、自分以外のコードがロックを取得してデッドロックにつながる可能性があります。その他の問題については、 信頼性ベストプラクティス を参照してください。

インスタンスをロックするときは注意してください。たとえば、C#のlock(this)やVisual BasicのSyncLock(Me)などです。タイプの外部にあるアプリケーション内の他のコードがオブジェクトをロックすると、デッドロックが発生する可能性がありますoccur

0
Teoman shipahi