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

更新 : 2007 年 11 月

lock キーワードは、指定のオブジェクトに対する相互排他ロックを取得し、ステートメントを実行し、ロックを解放するステートメント ブロックをクリティカル セクションとしてマークします。このステートメントの形式は、次のとおりです。

Object thisLock = new Object();
lock (thisLock)
{
    // Critical code section.
}

詳細については、「スレッドの同期 (C# プログラミング ガイド)」を参照してください。

解説

lock キーワードによって、あるスレッドがコードのクリティカル セクションになっているときは、別のスレッドはクリティカル セクションにはなりません。ロックされたコードを別のスレッドが使おうとすると、オブジェクトが解放されるまで待機 (ブロック) します。

スレッドについては、「スレッド処理 (C# プログラミング ガイド)」で説明します。

lock キーワードは、ブロックの最初に Enter を呼び出し、ブロックの最後に Exit を呼び出します。

一般に、public 型またはコードの制御範囲外にあるインスタンスに対してロックしないようにしてください。lock (this)、lock (typeof (MyType))、および lock ("myLock") などの一般的な構造は、このガイドラインに反しています。

  • インスタンスに対してパブリックにアクセスできる場合には、lock (this) が問題になります。

  • MyType に対してパブリックにアクセスできる場合には、lock (typeof (MyType)) が問題になります。

  • プロセス内で同じ文字列を使用する他のコードは同じロックを共有するので、lock(gmyLockh) が問題になります。

ロックする 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 will never be 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# 言語仕様」の次のセクションを参照してください。

  • 5.3.3.18 lock ステートメント

  • 8.12 lock ステートメント

参照

処理手順

Monitorによる同期化の技術サンプル

待機による同期化の技術サンプル

概念

C# プログラミング ガイド

Monitor

インタロックされた操作

AutoResetEvent

参照

スレッド処理 (C# プログラミング ガイド)

C# のキーワード

ステートメントのキーワード (C# リファレンス)

MethodImplAttributes

Mutex

スレッドの同期 (C# プログラミング ガイド)

その他の技術情報

C# リファレンス