次のコード:
lock (_syncRoot)
{
// Do stuff
}
コンパイラによって次のように変換されます。
Monitor.Enter(_syncRoot)
try
{
// Do stuff
}
finally
{
Monitor.Exit(_syncRoot);
}
これはナイーブな(そして古い)実装であり、実際には.NET 4.0では実装は多かれ少なかれこれです(完全なリファレンスについてはEricのブログを参照してください)。
bool locked = false;
try
{
Monitor.Enter(_syncRoot, ref locked);
}
finally
{
if (locked)
Monitor.Exit(_syncRoot);
}
編集済み
それは問題がどのようにMonitor.Enter()
機能するかということです。ええと、デフォルトのMono実装はセマフォを使用してロックを取得しますが、Microsoft.NET実装は動作が異なります。
段落が私の注意を引いたときに(Joe Duffyによる)並行Windowsプログラミングを読んでいたとき、私の最初の答えは「いいえ、一般的な場合にはパフォーマンスが良くない可能性があるため、回転を使用しません」と述べました。正解は「はい、.NETMonitor
はスピニングを使用します」です。.NETMonitor
とWindowsの両方のクリティカルセクションは、カーネルオブジェクトの真の待機にフォールバックする前に、短いスピンを実行します。このアルゴリズムは「2フェーズロックプロトコル」と呼ばれ、コンテキストスイッチとカーネル遷移が非常に拡張的であるため適切です。マルチプロセッサマシンでは、回転によって両方を回避できます。
さらに、これらは実装の詳細であり、リリースごとに変更される可能性があることを忘れないでください(または、JITコンパイラーのためにアルゴリズムがハードウェアごとに異なる可能性があります)。