lock ステートメント (C# リファレンス)lock Statement (C# Reference)

lock キーワードは、ステートメント ブロックをクリティカル セクションとして指定します。このためには、特定のオブジェクトの相互排他ロックを取得し、ステートメントを実行して、ロックを解放します。The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement, and then releasing the lock. 次の例では、lock ステートメントが使用されています。The following example includes a lock statement.

class Account  
{  
    decimal balance;  
    private Object thisLock = new Object();  

    public void Withdraw(decimal amount)  
    {  
        lock (thisLock)  
        {  
            if (amount > balance)  
            {  
                throw new Exception("Insufficient funds");  
            }  
            balance -= amount;  
        }  
    }  
}  

詳細については、「スレッドの同期」を参照してください。For more information, see Thread Synchronization.

コメントRemarks

lock キーワードは、コードのクリティカル セクションに複数のスレッドが同時に進入することを防ぐ働きをします。The lock keyword ensures that one thread does not enter a critical section of code while another thread is in the critical section. これから実行しようとしているコードがロックされている場合、別のスレッドは、そのオブジェクトが解放されるまで待機 (ブロック) 状態になります。If another thread tries to enter a locked code, it will wait, block, until the object is released.

スレッド処理については、「スレッド処理」を参照してください。The section Threading discusses threading.

lock キーワードは、ブロックの先頭で Enter を呼び出し、ブロックの末尾で Exit を呼び出します。The lock keyword calls Enter at the start of the block and Exit at the end of the block. lock ステートメントの実行を待っているスレッドを Interrupt で中断すると、ThreadInterruptedException がスローされます。A ThreadInterruptedException is thrown if Interrupt interrupts a thread that is waiting to enter a lock statement.

一般に、public 型 (つまり、コードの制御が及ばないインスタンス) をロックすることは避けてください。In general, avoid locking on a public type, or instances beyond your code's control. lock (this)lock (typeof (MyType))lock ("myLock") は、このガイドラインに違反する代表的なコンストラクトです。The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock") violate this guideline:

  • lock (this) は、このインスタンスにパブリックにアクセスできる場合に問題となります。lock (this) is a problem if the instance can be accessed publicly.

  • lock (typeof (MyType)) は、MyType にパブリックにアクセスできる場合に問題となります。lock (typeof (MyType)) is a problem if MyType is publicly accessible.

  • lock("myLock") が問題となる理由は、同じ文字列を使用するコードがプロセス内に他にも存在した場合、そのコードも同じロックを共有するためです。lock("myLock") is a problem because any other code in the process using the same string, will share the same lock.

private オブジェクトを定義してロックの適用対象を限定するか、private static オブジェクト変数を定義して、すべてのインスタンスに共通するデータを保護することをお勧めします。Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.

lock ステートメントの本体で await キーワードを使用することはできません。You can't use the await keyword in the body of a lock statement.

Example

次のサンプルでは、C# でロックされていないスレッドの簡単な使用例を示しています。The following sample shows a simple use of threads without locking in 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

Example

次のサンプルでは、スレッドと lock を使用しています。The following sample uses threads and lock. lock ステートメントが存在する限り、このステートメント ブロックはクリティカル セクションとなり、balance が負の数になることはありません。As long as the lock statement is present, the statement block is a critical section and balance will never become a negative number.

// 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();
        }
        
        //block main thread until all other threads have ran to completion.
        foreach (var t in threads)
            t.Join();
    }
}

C# 言語仕様C# Language Specification

詳細については、「C# 言語の仕様」を参照してください。For more information, see the C# Language Specification. 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。The language specification is the definitive source for C# syntax and usage.

参照See Also

MethodImplAttributes
Mutex
C# リファレンスC# Reference
C# プログラミング ガイドC# Programming Guide
スレッド化Threading
C# のキーワードC# Keywords
ステートメントのキーワードStatement Keywords
Monitor
インタロックされた操作Interlocked Operations
AutoResetEventAutoResetEvent
スレッドの同期Thread Synchronization