技術的には、これは悪い考えです。
using System;
class Foo {
static object foo = new object();
static void Main() {
lock (foo) {
foo = new object();
}
}
}
Main()
方法がにコンパイルされます:
.method private static hidebysig
default void Main() cil managed
{
// Method begins at RVA 0x2100
.entrypoint
// Code size 35 (0x23)
.maxstack 3
.locals init (
object V_0)
IL_0000: ldsfld object Foo::foo
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call void class [mscorlib]System.Threading.Monitor::Enter(object)
.try { // 0
IL_000c: newobj instance void object::'.ctor'()
IL_0011: stsfld object Foo::foo
IL_0016: leave IL_0022
} // end .try 0
finally { // 0
IL_001b: ldloc.0
IL_001c: call void class [mscorlib]System.Threading.Monitor::Exit(object)
IL_0021: endfinally
} // end handler 0
IL_0022: ret
} // end of method Foo::Main
これは(手で逆コンパイル)以下のソースに対応する:
static void Main() {
object V_0 = foo;
Monitor.Enter(V_0);
try {
foo = new object();
} finally {
Monitor.Exit(V_0);
}
}
だからオブジェクトこれC#ソースファイルを検討がロックされている場合は、ローカルに格納されます。これにより、フィールドに格納されているオブジェクト参照が置き換えられてもオブジェクトのモニタが解放されます。この方法だけではデッドロックは発生せず、すでにMonitor.Enter()
にブロックされている他のスレッドは、このスレッドがロックを解除するまで通常どおりブロックし続けます。しかし
、あなたはアクティブなスレッドのリリースはロックが新しいオブジェクトのロックを取得することになるので、に2つのスレッドがあることができ前にオブジェクトが、を再割り当てしている後、この方法に入り、任意のスレッド同時にロックブロック。
もっと良い解決策は、別のオブジェクトを使用して代わりにロックすることです。私は通常、クラスSystem.Object
(またはちょうどobject
)の何かを使用しているのは、それが行うことがmutexとして動作しているからです。これにより、すべてのスレッドが同じオブジェクトにロックされ、他のオブジェクト参照が変更されるようになります。ロックされていない値の型を変更するためにロックする必要がある場合にも、これは便利な方法です。
コードは書かれていますが、F5ボタンが見つからないため質問を投稿する時間がかかりましたか? –
私はそれをテストしていますが、そこに他の隠れたものがあるかもしれないと思っています。たとえば、ロックが取られないか、上書きされた後に消えるか、データが失われる可能性があります。私はエッジのケースを考えているが、私は新しいので、私は何を尋ねるのか分からない可能性があります。質問を文字通り取って、私の意図を見てはいけません。 – LamonteCristo
私はあまりにも皮肉なものとして出くわしていませんでした。私が謝罪した場合、私はちょうど(そして多分それはあなたがそこでの方法の99%であることを知っています)、ちょうどそれを試して見てみませんか?そして@Andyが言及したように、[lock](http://msdn.microsoft.com/en-us/library/c5kehkcz%28v=vs.71%29.aspx)は参照を保持しているので、良い考えではありませんそれがロックされている間にそれを変更する。 –