3 out of 6 rated this helpful Rate this topic

lock Statement (C# Reference)

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. 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 (C# and Visual Basic).

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 (C# and Visual Basic) discusses threading.

The lock keyword calls Enter at the start of the block and Exit at the end of the block. A ThreadInterruptedException is thrown if Interrupt interrupts a thread that is waiting to enter a lock statement.

In general, avoid locking on a public type, or instances beyond your code's control. The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock") violate this guideline:

  • lock (this) is a problem if the instance can be accessed publicly.

  • lock (typeof (MyType)) is a problem if MyType is publicly accessible.

  • lock("myLock") is a problem because any other code in the process using the same string, will share the same lock.

Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.

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



The following sample uses threads and lock. 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();
            }
        }
    }



For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

Did you find this helpful?
(2000 characters remaining)
Community Content Add
Annotations FAQ
Does not lock own thread
you could write something like that:

    public void TestMethod()
    {
      lock (m_lockObject)
      {
       TestMethod();
       //break condition
      }
    }

and it will NOT wait before the lock statement
(even though you shouldn´t write something like that :) )

pulp -- The lock statement assures that *another* thread of execution cannot enter the critical section. If one thread entered TestMethod(), locked on m_lockObject, recursively called TestMethod() again, and tried to obtain a lock on m_lockObject again (even though it is the same thread), it would be possible for a single thread to deadlock itself, ensuring that the critical section could never be exited. This would be *bad*.

Pumps UI messages

Although its hard to find documentation, lock uses a wait that pumps UI messages. This quote, from the article on Thread.Join, is the nearest I can find to it:
"Blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage pumping"