Wednesday 29 March 2017

Threading 06 Signalling via EventWaitHandle

signalling via the EventWaitHandle method involves signalling between threads that one can continue, while the other waits. it facilitates threads waiting for each other at different intervals and signalling to each other that anyone waiting can start.

let's take a look at this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace pc.SignallingEventWaitHandleWithNumbers
{
    class Program
    {
        static Random rnd = new Random(DateTime.Now.Millisecond);
        static void Main(string[] args)
        {
            var tOdd = new Thread(Print);
            var tEven = new Thread(Print);

            tOdd.Start(Enumerable.Range(0, 20).Where(i => i % 2 == 1));
            tEven.Start(Enumerable.Range(0, 20).Where(i => i % 2 == 0));
        }

        static void Print(object o) {
            var nums = o as IEnumerable<int>;
            foreach (var n in nums)
            {
                Thread.Sleep(rnd.Next(200, 700));
                Console.Write($"{n} ");
            }
        }
    }
}


here we create two threads that print number onto the console at staggering intervals, one thread has even numbers one thread has odd numbers. Each thread prints its own number sequentially but because of the varying delays between prints the numbers come off as staggered.

by leveraging the EventWaitHandler we have the ability to send signals between threads

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace pc.SignallingEventWaitHandleWithNumbers
{
    class Program
    {
        static Random rnd = new Random(DateTime.Now.Millisecond);
        struct Data
        {
            public IEnumerable<int> Nums { get; private set; }
            public EventWaitHandle SignalHandler { get; private set; }

            public Data(IEnumerable<int> Nums, EventWaitHandle SignalHandler)
            {
                this.Nums = Nums;
                this.SignalHandler = SignalHandler;
            }
        }
        static void Main(string[] args)
        {
            var tOdd = new Thread(Print);
            var tEven = new Thread(Print);

            //by setting initialstate to true, the first signal handler wait
            //does not need to be signaled, it recieves a signal by default
            using (var sh = new EventWaitHandle(true, EventResetMode.AutoReset))
            {
                tEven.Start(new Data(Enumerable.Range(0, 20).Where(i => i % 2 == 0), sh));

                //enuser that tEven starts first
                Thread.Sleep(100);
                tOdd.Start(new Data(Enumerable.Range(0, 20).Where(i => i % 2 == 1), sh));

                //wait for both threads to join method not to exit using before
                //finished with SignalHandler
                tEven.Join();
                tOdd.Join();
            }
        }

        static void Print(object o)
        {
            var data = (Data)o;
            foreach (var n in data.Nums)
            {
                //wait for signal
                data.SignalHandler.WaitOne();
                Thread.Sleep(rnd.Next(200, 700));
                Console.Write($"{n} ");
                //send signal
                data.SignalHandler.Set();
            }
        }
    }
}


As One thread waits for a signal the other prints its number and signals that it's complete and waits for a return signal.