Saturday, 25 March 2017

Threading 05 Signalling via CountdownEvent

signalling is way that that threads can communicate or signal each other, there are two types of signalling that can be implemented
  • CountDownEvent which we'll cover in this post
  • EventWaitHandle which we'll look at in the next post
the CountDownEvent signaling mechanism basically creates a barrier (I use this term loosely) that expects a certain number of signals before it will continue, first lets look at the implementation without the use of signalling

using System;
using System.Threading;

namespace pc.ThreadSignalling
{
    class Program
    {
        struct Data {
            public int Delay { get; set; }
            public string Value { get; set; }
            public Data(int Delay, string Value) {
                this.Delay = Delay;
                this.Value = Value;
            }
        }
        static void Main(string[] args)
        {
            var threads = new Thread[6];
            var data = "Hello world my name is Pawel".Split(' ');

            for (int i = 0, delay = 500; i < threads.Length; i++, delay += 500)
            {
                threads[i] = new Thread(Print);
                threads[i].Start(new Data(delay, data[i]));
            }
           
            //wait for each thread to finish before continuing with the main
            foreach (var t in threads)
                t.Join();

            Console.WriteLine("Woot Woot");
        }
        static void Print(object o) {
            var data = (Data)o;
            Thread.Sleep(data.Delay);
            Console.WriteLine(data.Value + " ");
        }
    }
}


Above we join all of our threads to the main before continuing to print out "Woot Woot" now we can accomplish the same thing using countdownevent

using System;
using System.Threading;

namespace pc.ThreadSignalling
{
    class Program
    {
        public struct Data
        {
            public int Delay { get; set; }
            public string Value { get; set; }
            public CountdownEvent cdEvent { get; set; }
            public Data(int Delay, string Value, CountdownEvent cdEvent)
            {
                this.Delay = Delay;
                this.Value = Value;
                this.cdEvent = cdEvent;
            }
        }
        static void Main(string[] args)
        {
            using (var cdEvent = new CountdownEvent(6))
            {
                var threads = new Thread[6];
                var data = "Hello world my name is Pawel".Split(' ');

                for (int i = 0, delay = 500; i < threads.Length; i++, delay += 500)
                {
                    threads[i] = new Thread(Print);
                    threads[i].Start(new Data(delay, data[i], cdEvent));
                }

                //Wait for 6 signals before continuing
                cdEvent.Wait();
            }

            Console.WriteLine("WOot woot");
        }

        static void Print(object o)
        {
            var data = (Data)o;
            Thread.Sleep(data.Delay);
            Console.Write(data.Value + " ");
            data.cdEvent.Signal();
        }
    }
}


In the above instead of joining all the threads in the main, we have each thread signal that it's in a state that can pass the cdEvent.Wait() barrier.