lock ステートメント (C# リファレンス)
lock キーワードは、指定のオブジェクトに対する相互排他ロックを取得し、ステートメントを実行し、ロックを解放するステートメント ブロックをクリティカル セクションとしてマークします。 このステートメントの形式は、次のとおりです。
Object thisLock = new Object();
lock (thisLock)
{
// Critical code section.
}
詳細については、「スレッドの同期 (C# および Visual Basic)」を参照してください。
解説
lock キーワードによって、あるスレッドがコードのクリティカル セクションになっているときは、別のスレッドはクリティカル セクションにはなりません。 ロックされたコードを別のスレッドが使おうとすると、オブジェクトが解放されるまで待機 (ブロック) します。
スレッドについては、「スレッド処理 (C# および Visual Basic)」で説明します。
lock キーワードは、ブロックの最初に Enter を呼び出し、ブロックの最後に Exit を呼び出します。
一般に、public 型またはコードの制御範囲外にあるインスタンスに対してロックしないようにしてください。 lock (this)、lock (typeof (MyType))、および lock ("myLock") などの一般的な構造は、このガイドラインに反しています。
インスタンスに対してパブリックにアクセスできる場合には、lock (this) が問題になります。
MyType に対してパブリックにアクセスできる場合には、lock (typeof (MyType)) が問題になります。
プロセス内で同じ文字列を使用する他のコードは同じロックを共有するので、lock("myLock") が問題になります。
ロックする private オブジェクトを定義するか、すべてのインスタンスに共通するデータを保護するために private static オブジェクト変数を定義することをお勧めします。
使用例
C# でのロックされていないスレッドの簡単な使用例を次に示します。
//using System.Threading;
class ThreadTest
{
public void RunMe()
{
Console.WriteLine("RunMe called");
}
static void Main()
{
ThreadTest b = new ThreadTest();
Thread t = new Thread(b.RunMe);
t.Start();
}
}
// Output: RunMe called
次の例では、スレッドおよび lock が使用されています。 lock ステートメントが存在する限り、ステートメント ブロックはクリティカル セクションであり、balance は負の数にはなりません。
// using System.Threading;
class Account
{
private Object thisLock = new Object();
int balance;
Random r = new Random();
public Account(int initial)
{
balance = initial;
}
int Withdraw(int amount)
{
// This condition never is true unless the lock statement
// is commented out.
if (balance < 0)
{
throw new Exception("Negative Balance");
}
// Comment out the next line to see the effect of leaving out
// the lock keyword.
lock (thisLock)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0; // transaction rejected
}
}
}
public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}
class Test
{
static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account(1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}
C# 言語仕様
詳細については、「C# 言語仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。