Tuesday 21 March 2017

Threading 04 Deadlocks

Now when using the locks in threads we have to be careful to avoid a deadlock scenario, deadlocks occur when two threads are waiting for each other to release locks, so let's say we start two threads at the same time, ThreadA and ThreadB, now they both use the same two locks Lock1 and Lock2, but in reverse order, that is:
  • threadA uses lock1 and then lock2
  • threadB uses lock2 with then lock1
so what happens is since both threads a and b start at the same time, they use locks 1 & 2 respectively, then inside their outer locks thread A now wants to use lock2 and threadB wants to use Lock1 however since both locks are already in use neither thread can continue thus creating a deadlock.

using System;
using System.Threading;

namespace pc.DeadlockExample
{
    class Program
    {

        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();

            var ThreadA = new Thread(() =>
            {
                lock (lock1)
                {
                    Console.WriteLine($"I'm ThreadA I'm using lock A");
                    lock (lock2)
                    {
                        Console.WriteLine($"I'm ThreadA I'm using lock A & B");
                    }
                }
            });

            var ThreadB = new Thread(() =>
            {
                lock (lock2)
                {

                    Console.WriteLine($"I'm ThreadB I'm using lock B");
                    lock (lock1)
                    {
                        Console.WriteLine($"I'm ThreadB I'm using locks A & B");
                    }
                }
            });

            ThreadA.Start();
            ThreadB.Start();
        }
    }
}


to avoid such a deadlock we have to ensure that either our threads don't share locks or that we request our locks in the same order in both threads to give them an opportunity to finish.

using System;
using System.Threading;

namespace pc.DeadlockExample
{
    class Program
    {

        static void Main(string[] args)
        {
            object lock1 = new object();
            object lock2 = new object();

            var ThreadA = new Thread(() =>
            {
                lock (lock1)
                {
                    Console.WriteLine($"I'm ThreadA I'm using lock A");
                    lock (lock2)
                    {
                        Console.WriteLine($"I'm ThreadA I'm using lock A & B");
                    }
                }
            });

            var ThreadB = new Thread(() =>
            {
                lock (lock1)
                {
                    Console.WriteLine($"I'm ThreadB I'm using lock B");
                    lock (lock2)
                    {
                        Console.WriteLine($"I'm ThreadB I'm using locks A & B");
                    }
                }
            });

            ThreadA.Start();
            ThreadB.Start();
        }
    }
}


now in our above example whichever thread grabs lock1 will prevent the other thread from using it until it's done, thus preventing a deadlock scenario