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

Monday, 20 March 2017

Threading 03 Locking

So we've played around a bit with threads, but we haven't really made them interact with each other. What we are going to build is a simple pick a straw simulation, we're going to create a repository of straws with long and short straws, then we are going to have an equal number of threads pull the straws and see what happens.

So first let's create an enum of long and short straws.

enum Straw { Long, Short }

We create our enum at our class level so that we can share it between all of our classes, generally I put all of my enums inside of their own namespace and just include the namespace in the using statements where needed.

using System;
using System.Linq;
using System.Threading;

namespace pc.ThreadLock
{
    enum Straw { Long, Short }
}


next let's create a straws class, this would be our collection of straws that our threads are going to pull. we are going to leverage a class indexer for our straws class, we are going to create a get accessor that removes the straw from the backing collection and resizes it.

using System;
using System.Linq;
using System.Threading;

namespace pc.ThreadLock
{
    enum Straw { Long, Short }

    class Straws
    {
        public int Count { get { return _straws.Count(); } }
        Straw[] _straws;

        public Straw this[int Index]
        {
            get
            {
                var pulledStraw = _straws[Index];

                //shift straws from pulled one left and resize array
                for (; Index + 1 < _straws.Length; Index++)
                    _straws[Index] = _straws[Index + 1];
                Array.Resize(ref _straws, _straws.Length - 1);

                return pulledStraw;
            }
        }

        public Straws(int NumOfStraws, int NumOfShortStraws = 1)
        {
            _straws = new Straw[NumOfStraws];

            while (NumOfShortStraws > 0)
            {
                //pick random index for short straw, if selected index
                //already has short straw, try again.
                var shortStrawIndex = Program.rnd.Next(NumOfStraws);

                if (_straws[shortStrawIndex] == Straw.Short)
                    continue;

                _straws[shortStrawIndex] = Straw.Short;
                NumOfShortStraws--;
            }
        }
    }
}


Finally we are going to create our threads inside the main method which are going to pull the straws from our straw class.

class Program
{
    public static Random rnd = new Random(DateTime.Now.Millisecond);
    static Straws Straws = new Straws(5,2);

    static void Main(string[] args)
    {
        var Pawel = new Thread(new ThreadStart(PullStraw));
        Pawel.Name = "Pawel";

        var Magda = new Thread(new ThreadStart(PullStraw));
        Magda.Name = "Magda";

        var Jakub = new Thread(new ThreadStart(PullStraw));
        Jakub.Name = "Jakub";

        var Tomek = new Thread(new ThreadStart(PullStraw));
        Tomek.Name = "Tomek";

        var Marin = new Thread(new ThreadStart(PullStraw));
        Marin.Name = "Marin";

        var Threads = new Thread[] { Pawel, Magda, Jakub, Tomek, Marin };

        foreach (var t in Threads)
            t.Start();
    }

    static void PullStraw()
    {
        Straw PulledStraw = Straws[rnd.Next(Straws.Count - 1)];
        var output = $"{Thread.CurrentThread.Name} pulled {PulledStraw.ToString()}";
        Console.WriteLine(output);
    }

}

now if we run our application the way it currently sits we are going to notice some bizarre behavior, from too many short straws, to no short straws, to index out of bounds exceptions, this is because we have 5 threads manipulating the same straws data source at the same time. To fix our concurrency issues we need to lock the access to our straws class down so that each thread can access it individually and keep it from being corrupted, by multiple threads trying to make changes simultaneously.

to do this is actually pretty straight forward we are going to need an object to use as a lock outside of our threads scope, so at the program class level is fine.

using System;
using System.Linq;
using System.Threading;

namespace pc.ThreadLock
{
    enum Straw { Long, Short }
    class Straws
    {
        public int Count { get { return _straws.Count(); } }
        Straw[] _straws;

        public Straw this[int Index]
        {
            get
            {
                var pulledStraw = _straws[Index];

                //shift straws from pulled one left and resize array
                for (; Index + 1 < _straws.Length; Index++)
                    _straws[Index] = _straws[Index + 1];
                Array.Resize(ref _straws, _straws.Length - 1);

                return pulledStraw;
            }
        }

        public Straws(int NumOfStraws, int NumOfShortStraws = 1)
        {
            _straws = new Straw[NumOfStraws];

            while (NumOfShortStraws > 0)
            {
                //pick random index for short straw, if selected index
                //already has short straw, try again.
                var shortStrawIndex = Program.rnd.Next(NumOfStraws);
                if (_straws[shortStrawIndex] == Straw.Short)
                    continue;
                _straws[shortStrawIndex] = Straw.Short;
                NumOfShortStraws--;
            }
        }
    }

    class Program
    {
        public static Random rnd = new Random(DateTime.Now.Millisecond);
        static Straws Straws = new Straws(5, 2);

        //Our lock to prevent concurrent access to the straws object
        static object _lock = new object();

        static void Main(string[] args)
        {
            var Pawel = new Thread(new ThreadStart(PullStraw));
            Pawel.Name = "Pawel";

            var Magda = new Thread(new ThreadStart(PullStraw));
            Magda.Name = "Magda";

            var Jakub = new Thread(new ThreadStart(PullStraw));
            Jakub.Name = "Jakub";

            var Tomek = new Thread(new ThreadStart(PullStraw));
            Tomek.Name = "Tomek";

            var Marin = new Thread(new ThreadStart(PullStraw));
            Marin.Name = "Marin";

            var Threads = new Thread[] { Pawel, Magda, Jakub, Tomek, Marin };

            foreach (var t in Threads)
                t.Start();
        }

        static void PullStraw()
        {
            Straw PulledStraw;

            //restrict access to just one thread at a time
            lock (_lock)
            {
                PulledStraw = Straws[rnd.Next(Straws.Count - 1)];
            }

            var output = $"{Thread.CurrentThread.Name} pulled {PulledStraw.ToString()}";
            Console.WriteLine(output);
        }
    }
}


and that's it we've implemented locking for our threads