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.