Deadlock Sample in C#


A deadlock is a situation which can be described as follows:

"When two or more competing processes are waiting for the other to finish and hence none of them making it to completion is called as a deadlock situation".

Let’s see an example with deadlock.

In the below example, DoWork1 first acquires lock on staticObjLockA and immediately yields for one second using Thread.Sleep(1000). In the meantime DoWork2 acquires lock on staticObjLockB. Now, DoWork1 is waiting to acquire lock on staticObjLockB (which is already acquired by DoWork2) and DoWork2 is waiting to acquire lock on staticObjLockA (which is already acquired by DoWork1). Hence, a deadlock situation.

 

    public class DeadlockSamples
    {
        private static object staticObjLockA = new Object();
        private static object staticObjLockB = new Object();

        public static void Main()
        {
            // Initialize thread with address of DoWork1
            Thread thread1 = new Thread(DoWork1);

            // Initilaize thread with address of DoWork2
            Thread thread2 = new Thread(DoWork2);

            // Start the Threads.
            thread1.Start();
            thread2.Start();

            thread1.Join();
            thread2.Join();

            // This statement will never be executed.
            Console.WriteLine("Done Processing...");
        }

        private static void DoWork1()
        {
            lock (staticObjLockA)
            {
                Console.WriteLine("Trying to acquire lock on staticObjLockB");

                // Sleep to yield.
                Thread.Sleep(1000);
                lock (staticObjLockB)
                {
                    // This block will never be executed.
                    Console.WriteLine("In DoWork1 Critical Section.");
                    // Access some shared resource here.
                }
            }
        }

        private static void DoWork2()
        {
            lock (staticObjLockB)
            {
                Console.WriteLine("Trying to acquire lock on staticObjLockA");
                lock (staticObjLockA)
                {
                    // This block will never be executed.
                    Console.WriteLine("In DoWork2 Critical Section.");
                    // Access some shared resource here.
                }
            }
        }
    }

 

One possible solution to avoid the above deadlock situation is using Monitor.TryEnter instead of lock. Monitor.TryEnter method will try to acquire lock only for the time interval specified.

In the below example, DoWork1 will try to acquire lock on staticObjLockB for 5 seconds. If lock cannot be acquired it prints a message and returns.

    public class DeadlockSamplesMonitor
    {
        private static object staticObjLockA = new Object();
        private static object staticObjLockB = new Object();

        public static void Main()
        {
            // Initialize thread with address of DoWork1
            Thread thread1 = new Thread(DoWork1);

            // Initilaize thread with address of DoWork2
            Thread thread2 = new Thread(DoWork2);

            // Start the Threads.
            thread1.Start();
            thread2.Start();

            thread1.Join();
            thread2.Join();
            
            Console.WriteLine("Done Processing...");
        }

        private static void DoWork1()
        {
            lock (staticObjLockA)
            {
                Console.WriteLine("Trying to acquire lock on staticObjLockB");

                // Sleep to yield.
                Thread.Sleep(1000);

                // This will try to acquire lock for 5 seconds.
                if (Monitor.TryEnter(staticObjLockB, 5000))
                {
                    try
                    {
                        // This block will never be executed.
                        Console.WriteLine("In DoWork1 Critical Section.");
                        // Access some shared resource here.
                    }
                    finally
                    {
                        Monitor.Exit(staticObjLockB);
                    }
                }
                else
                {
                    // Print lock not able to acquire message.
                    Console.WriteLine("Unable to acquire lock, exiting DoWork1.");
                }                
            }
        }

        private static void DoWork2()
        {
            lock (staticObjLockB)
            {
                Console.WriteLine("Trying to acquire lock on staticObjLockA");
                lock (staticObjLockA)
                {                    
                    Console.WriteLine("In DoWork2 Critical Section.");
                    // Access some shared resource here.
                }
            }
        }
    }