C# Musings : A quick Latch implementation

Latch

In threading the notion of a Latch is a signal which will be set at most once.  Using a latch and in the following example I am demonstrating how you can initialize and start a number of threads, allow the threads to set themselves up, signal that they are ready and only when all threads are ready will the Latch be released and all threads can go on and do what they were intended to.

There are many ways to skin a cat but this just shows one way of doing this using the notion of  a Latch.  As the title says I have created a quick implementation of a Latch, just for the purposes of demonstration but it does what is needed.  For my implementation I have used the ManualResetEvent and if we read a snippet from the MSDN documentation, you will understand the reason for my choice:

When the controlling thread completes the activity, it calls Set to signal that the waiting threads can proceed. All waiting threads are released.

The reason I have not used AutoResetEvent is because calling Set on an AutoResetEvent will only release one waiting thread, where as ManualResetEvent will release all.  In my implementation I also want to be aware of how many threads are to be expected so that the latch can automatically release once if has been notified by all threads which are “in the race.” To do this and whilst keeping concurrency in mind, I have gone for using the Interlocked.Increment method.  One final point, keeping with the intended behavior of a Latch, in that it should only be set once, I have put in a boolean variable which will only allow execution when it has a value of false.

Latch

public class Latch
	{
		private int _amountToWaitFor;

		public ManualResetEvent WaitSignal { get; private set; }
		private int ReadyCount;
		private bool _released;

		public Latch (int amountToWaitFor)
		{
			_amountToWaitFor = amountToWaitFor;
			WaitSignal = new ManualResetEvent (false);
		}

		public void Acquire ()
		{
			if (!_released) {
				Console.WriteLine ("{0} Aquired Latch", Thread.CurrentThread.Name);
				if (Interlocked.Increment (ref ReadyCount) == _amountToWaitFor) {
					Console.WriteLine ("All threads have aquired latch");
					Console.WriteLine ("Releasing latch");
					_released = true;
					WaitSignal.Set ();
				}
			}
		}
	}

Encapsulation  is not completely there, as the ManualResetEvent is exposed meaning that it could be set outside of the Latch.  I will leave that for now but it is something which could be improved.  The example which I have used to demonstrate example usage of the above class is below:

	class MainClass
	{
		public static void Main (string[] args)
		{
			LatchExample ();
			Console.ReadLine ();
		}

		static void LatchExample ()
		{
			const int amountToWaitFor = 10;

			var latch = new Latch (amountToWaitFor);

			for (var i = 0; i < amountToWaitFor; i++) {
				var thread = new Thread (x =>
				{
					var latchReference = (Latch)x;
					latchReference.Acquire ();
					latchReference.WaitSignal.WaitOne ();

					Console.WriteLine ("Thread {0} started at {1}", Thread.CurrentThread.Name, DateTime.Now.Millisecond);
				});
				thread.Name = "Thread_" + i;
				thread.Start (latch);
			}
		}
	}

Cheers for now,

Andrew

UPDATE

I have looked over this again as having the ManualResetEvent has public and losing encapsulation I thought I would change it to be fully encapsulated.  The version below uses the Monitor class so that I can block the current Thread’s execution without blocking any other threads.  To do this, I have used the Monitor.Wait method which releases a lock allowing other Threads to continue execution.  Now that I have this, I am able to get rid of the ManualResetEvent as this achieves it another way, many ways to skin a cat and all that.

All a Thread need do now is to call the Aquire method on the latch once it is ready and this will block it until the latch is released.  One caveat of this is that if any of the threads do not call Aquire on the latch, they will wait indefinitely.  An upgrade to this could be to have a maximum wait time, which if expires will release the latch regardless.

NB://I realize I have spelled acquire incorrectly all the way through this. : -(

Better Latch

	class Latch
	{
		private static object _synclock = new object ();
		
		private int _amountToWaitFor;
		private int ReadyCount;
		private bool _released;

		public Latch (int amountToWaitFor)
		{
			_amountToWaitFor = amountToWaitFor;
		}

		public void Acquire ()
		{
			if (!_released) {
				lock (_synclock) {
					if (!_released) {
						Console.WriteLine ("{0} Aquired Latch", Thread.CurrentThread.Name);
						if (Interlocked.Increment (ref ReadyCount) == _amountToWaitFor) {
							Console.WriteLine ("All threads have aquired latch");
							Console.WriteLine ("Releasing latch");
							_released = true;
							Monitor.PulseAll(_synclock);
						}else{
							Monitor.Wait(_synclock);
						}
					}
				}
			}
		}
	}

And here is the updated example usage:

	class MainClass
	{
		public static void Main (string[] args)
		{
			LatchExample ();
			Console.ReadLine ();
		}

		static void LatchExample ()
		{
			const int amountToWaitFor = 10;
			
			var latch = new Latch (amountToWaitFor);
			
			for (var i = 0; i < 10; i++) {
				var thread = new Thread (x =>
				{
					var latchReference = (Latch)x;
					
					//Do some setup here
					
					//Once ready aquire the latch.
					//This will now block until all the threads have aquired the latch
					latchReference.Acquire ();
					
					Console.WriteLine ("Thread {0} started at {1}", Thread.CurrentThread.Name, DateTime.Now.Millisecond);
				});
				thread.Name = "Thread_" + i;
				thread.Start (latch);
			}
		}
	}
No Comments

Start the ball rolling by posting a comment on this article!

Leave a Reply




XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>