web-dev-qa-db-ja.com

ロックはどのように正確に機能しますか?

スレッドセーフではないオブジェクトを使用するためには、コードを次のようなロックでラップする必要があります。

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

そのため、複数のスレッドが同じコードにアクセスするとどうなりますか(ASP.NET Webアプリケーションで実行されているとします)。彼らはキューに入っていますか?もしそうなら彼らはどのくらい待つのだろうか?

ロックを使用することによるパフォーマンスへの影響は何ですか?

448
NLV

lockステートメントは、C#3.0によって次のように翻訳されました。

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

C#4.0 これは変更されました そして今それは次のように生成されます:

bool lockWasTaken = false;
var temp = obj;
try
{
    Monitor.Enter(temp, ref lockWasTaken);
    // body
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(temp); 
    }
}

Monitor.Enterが何をするのかについてのより多くの情報を見つけることができます ここ 。 MSDNを引用するには:

Enterを使用して、パラメータとして渡されたオブジェクトのモニタを取得します。他のスレッドがそのオブジェクトに対してEnterを実行したが、対応するExitをまだ実行していない場合、現在のスレッドは他のスレッドがオブジェクトを解放するまでブロックします。同じスレッドがブロックせずにEnterを複数回呼び出すことは正当です。ただし、オブジェクトを待機している他のスレッドがブロックを解除する前に、同数のExit呼び出しを呼び出す必要があります。

Monitor.Enterメソッドは無限に待機します。それは ではない タイムアウトします。

396
Steven

あなたが思うよりも簡単です。

Microsoft による:lockキーワードは、他のスレッドがクリティカルセクションにある間、1つのスレッドがコードのクリティカルセクションに入らないようにします。別のスレッドがロックされたコードを入力しようとすると、オブジェクトが解放されるまで待機し、ブロックされます。

lockキーワードは、ブロックの先頭で Enter を呼び出し、ブロックの最後で Exit を呼び出します。 lockキーワードは実際にはバックエンドで Monitor クラスを処理します。

例えば:

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

上記のコードでは、最初にスレッドがクリティカルセクションに入り、次にobjをロックします。別のスレッドが入ろうとすると、objもロックしようとします。これは最初のスレッドによってすでにロックされています。最初のスレッドがobjを解放するのを待つ必要があります。最初のスレッドが離れると、別のスレッドがobjをロックしてクリティカルセクションに入ります。

234
Umar Abbas

いいえ、彼らは並んでいません、彼らは寝ています

次の形式のロック文

lock (x) ... 

ここで、xは参照型の式です。これは、とまったく同じです。

var temp = x;
System.Threading.Monitor.Enter(temp); 
try { ... } 
finally { System.Threading.Monitor.Exit(temp); }

あなたはただそれらがお互いを待っていることを知る必要があります、そして1つのスレッドだけがブロックをロックするために入るでしょう、他は待つでしょう...

Monitorは十分に高速なので.netで書かれているので、 クラスMonitor with リフレクター を見てください。

43
Arsen Mkrtchyan

ロックは、他のスレッドがロックブロックに含まれるコードを実行するのをブロックします。ロックブロック内のスレッドが完了してロックが解放されるまで、スレッドは待機する必要があります。これは、マルチスレッド環境でのパフォーマンスに悪影響を及ぼします。これを行う必要がある場合は、ロックブロック内のコードが非常に迅速に処理できるようにする必要があります。データベースへのアクセスなどの費用のかかる活動を避けるようにしてください。

26
Andrew

パフォーマンスへの影響は、ロック方法によって異なります。あなたはここで最適化の良いリストを見つけることができます: http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/ /

基本的には、待機中のコードをスリープさせるので、できるだけロックしないようにしてください。あなたがロックの中にいくつかの重い計算または長続きするコード(例えばファイルアップロード)があるならば、それは多大なパフォーマンス損失をもたらします。

10
Simon Woker

Lockステートメント内の部分は1つのスレッドでしか実行できないため、他のすべてのスレッドはロックを保持しているスレッドが終了するまで無期限に待機します。これにより、いわゆるデッドロックが発生する可能性があります。

7
Mr47

lockステートメントは、 EnterExitおよびMonitorメソッドの呼び出しに変換されます。

lockステートメントは、ロックオブジェクトが解放されるのを無期限に待ちます。

7
Paolo Tedesco

lock は実際には隠されている Monitor class。

4
Euphoric