Wednesday, January 15, 2014

Lock Statement in C#

Lock statement can be really useful when you are writing multi threaded applications. Basically what lock statement does is, it monitors and prevents some particular blocks of code from being accessed simultaneously by multiple threads.

It's always good to go by an example. First I am creating a very simple multi threaded application without any lock statements. I am having a class there named “MyClass” which will have a single method.
public class MyClass
{
    public void MyMethodWithoutLock()
    {
        Thread.Sleep(5000);
        Console.WriteLine("Without Lock " + DateTime.Now);
    }
}
Inside the above method, let’s assume that I am doing some time consuming work and then I am printing out a message with the current time.

Inside the Main method, I am going to create a object of “MyClass” and I am going to call the “MyMethodWithoutLock” from some different threads.
class Program
{
    static void Main(string[] args)
    {
        MyClass oMyClass = new MyClass();
        List<Thread> threads = new List<Thread>();
 
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(oMyClass.MyMethodWithoutLock);
            threads.Add(t);
        }
 
        foreach (Thread t in threads)
        {
            t.Start();
        }
 
        Console.WriteLine(DateTime.Now);
    }
}
Here there is nothing complex, just some very simple multi threading. I have created a object of "MyClass" and created a variable to hold list of threads. Then I have added 5 threads to threads list which will call the “MyMethodWithoutLock” of my one and only object “oMyClass”. Finally I am starting all the threads at once and printing out the current time. Please note that in my Main method, I have created only a single object of “MyClass”

So the output will be as follows.
Pic1
Without Lock
As you can see after starting the treads at 11:35:01, all the threads has completed calling “MyMethodWithoutLock” simultaneously at 11:35:06. So the point here is all threads have been calling “MyMethodWithoutLock” at the same time which is a prefect concurrency.

Now let’s say, I have a scenario where I have two methods. One method should be called simultaneously and the other should not be called simultaneously. For this I can use the lock statement and let’s see how.

Hers is my modified class.
public class MyClass
{
    private Object thisLock = new Object();
 
    public void MyMethodWithoutLock()
    {
        Thread.Sleep(5000);
        Console.WriteLine("Without Lock " + DateTime.Now);
    }
 
    public void MyMethodWithLock()
    {
        lock (thisLock)
        {
            Thread.Sleep(5000);
            Console.WriteLine("With Lock " + DateTime.Now);
        }
    }
}
Inside Main, I will have some threads as previous, the only difference is, my threads will be calling both these two methods as below.
class Program
{
    static void Main(string[] args)
    {
        MyClass oMyClass = new MyClass();
        List<Thread> threads = new List<Thread>();
 
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(new ThreadStart(() =>
            {
                oMyClass.MyMethodWithoutLock();
                oMyClass.MyMethodWithLock();
            }));
            threads.Add(t);
        }
 
        foreach (Thread t in threads)
        {
            t.Start();
        }
 
        Console.WriteLine(DateTime.Now);
    }
}
Now the output will be as follows.
Pic2
With Lock
If you can see here, my set of threads has called “MyMethodWithoutLock” method simultaneously. But “MyMethodWithLock” method has been called by only one single thread at a time. After one thread completed executing “MyMethodWithLock” method, then another thread came in and has accessed “MyMethodWithLock”.

Now if you have read the above well, I have mentioned I have created only a single object of “MyClass”. Let’s modify the above code where I am creating several objects of “MyClass” and each thread will be accessing separate objects’ methods.
class Program
{
    static void Main(string[] args)
    {
        List<Thread> threads = new List<Thread>();
 
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(new ThreadStart(() =>
            {
                MyClass oMyClass = new MyClass();
                oMyClass.MyMethodWithoutLock();
                oMyClass.MyMethodWithLock();
            }));
            threads.Add(t);
        }
 
        foreach (Thread t in threads)
        {
            t.Start();
        }
 
        Console.WriteLine(DateTime.Now);
    }
}
So the output will be as follows.
Pic3
With Lock Different Objects
Now here what has happened is both the methods has been called simultaneously back again. This explains the very basic concept of the lock statement. That is lock will only be blocking some code from accessing multiple threads only when the code belongs to same object. If the threads are accessing same method of different objects and still you want to block some code from multi thread access, if you use lock statement, basically it’s not going to help you.

For more information,
   lock Statement (C# Reference)
   Thread Synchronization

I am uploading the sample to my SkyDrive, do enjoy.


So hope this helps. Appreciate your all feedback.

Happy Coding.

Regards,
Jaliya

2 comments:

  1. Hi Jaliya,

    Its a very nice article, love how you have explained everything in detail.

    Need a bit of explaining in some Threading that always confuses me.
    Could you Please explain the code snippet below :

    Thread t = new Thread(new ThreadStart(() =>
    {
    MyClass oMyClass = new MyClass();
    oMyClass.MyMethodWithoutLock();
    oMyClass.MyMethodWithLock();
    }));
    threads.Add(t);

    Could you just tell me what "new ThreadStart(() =>" part is ?? I am a bit confused.

    Warm Regards
    Richie

    ReplyDelete
    Replies
    1. Thank you so much for the nice comment. Now let me answer your question.

      The Thread class has constructors that take a ThreadStart delegate or a ParameterizedThreadStart delegate. Here I have used the constructor which takes ThreadStart delegate. Then using lambda expressions I have created an anonymous function which will be executed on that particular thread.

      It’s like this. Let’s say in MyClass, I have a helper method called “MyMethod” which in turn call MyMethodWithoutLock() and MyMethodWithLock().

      public void MyMethod()
      {
      MyMethodWithoutLock();
      MyMethodWithLock();
      }

      Then without using lambda expressions, I can just write,

      Thread t = new Thread(new ThreadStart(oMyClass.MyMethod));

      But why create extra methods, when you can simplify the code by writing anonymous functions.

      Delete