Geeks With Blogs

News

Series

Add to Technorati Favorites


An Archived Managed World This blog has moved to http://www.managed-world.com/blog

In this first stage of our Tour de BCL, we will be passing through the new Barrier class.

So what is a Barrier? Let’s take a look at the boring technical description for a Barrier:

A Barrier is a synchronization primitive that enforces the stopping of execution between a number of threads or processes at a given point and prevents further execution until all threads or processors have reached the given point.

I don’t know about you, but sometimes technical descriptions like the above just sound like “blah, blah, blah” to me. What does a Barrier really mean to me, as a developer. Let’s break it down a different way by looking at a specific real-life scenario.

Think of a Road Trip

Instead of looking at the technical description above, think of the concept of a road trip.

There are three friends, Mac, Charlie, and Dennis. They live in a small town south of Seattle but want to take a road trip up to Seattle. So Mac calls up Charlie and Dennis and says “Hey guys, let’s take a road trip to Seattle. Meet up at the local gas station and then we’ll all leave from there.” So now they all now they need to go to the local gas station, wait for all of them to show up, and then they’ll leave for Seattle together and follow each other there.

Barrier

Relating this scenario to some code, let’s say that Charlie, Mac, and Dennis are all individual threads that have one method of execution, the DriveToSeattle() method. Within that method, they are all going “to drive” to the same gas station and then continue to drive to Seattle.

If we don’t use the Barrier to synchronize the work (aka wait for each other to arrive at the gas station), each one of them will leave for Seattle the second they arrive at the gas station:

static void Main(string[] args)
{
    var charlie = new Thread(() => {
        DriveToSeattle("Charlie", TimeSpan.FromSeconds(1))
    }); 
    charlie.Start();

    var mac = new Thread(() => {
        DriveToSeattle("Mac", TimeSpan.FromSeconds(2))
    }); 
    mac.Start();

    var dennis = new Thread(() => {
        DriveToSeattle("Dennis", TimeSpan.FromSeconds(3))
    }); 
    dennis.Start();

    charlie.Join();
    mac.Join();
    dennis.Join();

    Console.ReadKey();
}

static void DriveToSeattle(string name, TimeSpan timeToGasStation)
{
    // Drive to gas station
    Console.WriteLine("[{0}] Leaving House", name);
    Thread.Sleep(timeToGasStation);
    Console.WriteLine("[{0}] Arrived at Gas Station", name);

    // Need to sync here

    // Perform some more work
    Console.WriteLine("[{0}] Leaving for Seattle", name);
}

BeforeBarrier

Well, that’s hardly a road trip. If I were in Mac’s or Charlie’s shoes when Dennis left for Seattle without me, I know I would be a little upset. We obviously don’t want that to happen. So we can use the new Barrier to make sure they all “wait up” for each other at the gas station.

Using the new Barrier class

So how do you use the new Barrier class? It’s actually quite simple.The cool thing is that there are really only three things you need to learn to use the Barrier for this simple type of scenario: a single constructor and two method calls (both of which take zero parameters). Yes, it’s that simple to use.

Let’s look at what our new code using Barrier looks like (the three bold lines are the new ones):

static Barrier sync;

static void Main(string[] args)
{
    sync = new Barrier(participantCount:3);

    var charlie = new Thread(() => {
        DriveToSeattle("Charlie", TimeSpan.FromSeconds(1))
    }); 
    charlie.Start();

    var mac = new Thread(() => {
        DriveToSeattle("Mac", TimeSpan.FromSeconds(2))
    }); 
    mac.Start();

    var dennis = new Thread(() => {
        DriveToSeattle("Dennis", TimeSpan.FromSeconds(3))
    }); 
    dennis.Start();

    charlie.Join();
    mac.Join();
    dennis.Join();

    Console.ReadKey();
}

static void DriveToSeattle(string name, TimeSpan timeToGasStation)
{
    // Drive to gas station
    Console.WriteLine("[{0}] Leaving House", name);
    Thread.Sleep(timeToGasStation);
    Console.WriteLine("[{0}] Arrived at Gas Station", name);

    // Need to sync here
    sync.SignalAndWait();

    // Perform some more work
    Console.WriteLine("[{0}] Leaving for Seattle", name);
}

AfterBarrier

You can see now that nobody leaves for Seattle until everybody has arrived at the gas station. Essentially, with every call to SignalAndWait(), the number of signals received by the barrier is incremented. Once the number of signals received reaches the number of participants the Barrier was constructed with, all threads are then allowed to continue execution. And that’s all it takes to leverage the new Barrier class being introduced into the BCL with .NET Framework 4.0.

But Jason... What is up with that line of code: “sync = new Barrier(participantCount:3);”? I mean, what the heck is “participantCount:3”? How is that valid syntax?

Well, that’s easy. This is a new feature in C# 4.0 called Named Parameters where you can actually use a parameter’s name to specify what a value applies to. This becomes very handy in two places: 1) when combined with Optional Parameters, and 2) when used to clarify “magic numbers” (or “magic strings”, “magic booleans”, etc.) without having to introducing a temporary variable.

In this case, I could have left out participantCount and written just “sync = new Barrier(3);”. But I personally don’t like a magic number like “3” just floating around like this and Named Parameters give me an easy way to provide more context about the value “3”.

In Closing

So let’s look back at that boring technical description again:

A Barrier is a synchronization primitive that enforces the stopping of execution between a number of threads or processes at a given point and prevents further execution until all threads or processors have reached the given point.

Think about it this way:

  • “stopping of execution between a number of threads...” = waiting for each other to arrive
  • “… at a given point” = the gas station
  • “prevents further execution until all threads… have reached the given point” = can’t leave for Seattle until everybody shows up

See? Nice and simple!

Barrier is a great new synchronization primitive to use when there is a known amount of work to do that is being done by different workers that all have common synchronization points. However, if the amount of work needing to be done is not well known beforehand, Barrier is not the greatest primitive to use. Next we’ll look at another new synchronization primitive coming in .NET Framework 4.0 that is great to use when the amount of work is not known: the CountdownEvent.

I hope you all enjoyed this first stage in our Tour de BCL. Until the next stage, we’ll see you later.

Posted on Monday, February 9, 2009 11:17 PM C# Dev Center , Concurrency , Development | Back to top


Comments on this post: An Intro to Barrier

# re: An Intro to Barrier
Requesting Gravatar...
That's a slick construct--I've had to roll my own Barrier on a couple of occasions, but I never had a good name for it like "Barrier".

I'm feeling strangely compelled to embark on a road trip to Seattle and try out this scenario.
Left by Marquis Marc on Feb 10, 2009 8:29 AM

# re: An Intro to Barrier
Requesting Gravatar...
Nice example, Jason. Reading this, my summary would be - Barrier'ed thread code executes and waits until all threads taking part in the Barrier'ed operation reach a common sync point (the Barrier) in their executing code. Once they're all there, they resume execution in reverse order to their order of arrival at the sync point.

Does Barrier offer the ability to say /which/ threads are to be kicked off together, or for the threads to say which Barrier they want to Join?
Left by Mark Smith on Feb 11, 2009 5:47 AM

# re: An Intro to Barrier
Requesting Gravatar...
I second Mark's question on barrier relation to the threads.

Basically, the issue I see with this is that I can see an exception (due to a bug or unexpected condition) leading to some threads being left waiting. I know u can restructure to avoid this, but then it isn't that clean ;)
Left by freddy on Feb 12, 2009 11:48 AM

# re: An Intro to Barrier
Requesting Gravatar...
I cant figure out the difference between waitAll on threads vs. barrier. Why do we need to use barrier if waitAll already works the same way?
Left by Mohan on Oct 22, 2009 5:43 PM

# re: An Intro to Barrier
Requesting Gravatar...
Great info. This worked for me. I too had an innovative construct like Marquis did.

G
Left by Fish Oil Supplements on Jan 26, 2010 2:41 PM

# re: An Intro to Barrier
Requesting Gravatar...
I'm having the same problem as Mohan. Can you please elaborate the difference between waitALL as he mentioned above?
Left by Internet Marketing Consultant on Aug 12, 2010 3:43 AM

# re: An Intro to Barrier
Requesting Gravatar...
awesome example!
Left by sdf on Aug 17, 2010 12:52 PM

# re: An Intro to Barrier
Requesting Gravatar...
yr this simple type of scenario is helpful for me!thx mate there.
Left by Desmond Hardnette on Mar 22, 2011 7:04 PM

# re: An Intro to Barrier
Requesting Gravatar...
Hi the same with TASK in .net 4 is :
-------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace BarrierBest
{
class Program
{
private static Barrier sync;
static void Main(string[] args)
{

sync = new Barrier(3,(barrier)=>{
Console.WriteLine("Current Phase :{0}", barrier.CurrentPhaseNumber);
});
Task t1 = new Task(() =>
{
DriveToSeattle("Bill",TimeSpan.FromSeconds(1));
});
t1.Start();

Task t2 = new Task(() =>
{
DriveToSeattle("Michael", TimeSpan.FromSeconds(2));
});
t2.Start();
Task t3 = new Task(() =>
{
DriveToSeattle("Oliver", TimeSpan.FromSeconds(3));
});
t3.Start();
Task.WaitAll();
//wait for inpout before exit
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}

static void DriveToSeattle(string name, TimeSpan timeToGasStation)
{
// Drive to gas station
Console.WriteLine("[{0}] Leaving House", name);
Thread.Sleep(timeToGasStation);
Console.WriteLine("[{0}] Arrived at Gas Station", name);
sync.SignalAndWait();
// Perform some more work
Console.WriteLine("[{0}] Leaving for Seattle", name);
}
}
}

-------------------------------------
Left by Bill Geronatsios on Jun 14, 2011 8:44 AM

# Thanks
Requesting Gravatar...
Thanks for writing this, I was really struggling over the crappy "Textbook" explanation of this.

Hey, you are very talented and should write a textbook on C# .NET... I would buy it
Left by Kathleen on Feb 06, 2017 11:48 AM

# re: An Intro to Barrier
Requesting Gravatar...
In reply to Mohan's question on how Barrier is different from WaitAll(), I'd say that in the case of WaitAll, it is the function starting the thread which waits on the different threads, and then would have to tell all the blocked threads to resume presumably with a manual reset event.

In the case of Barrier, each thread is blocking by itself, and then RESUMING by itself, once signalled by the operating system.
Left by Bharat on Feb 09, 2017 6:30 PM

Your comment:
 (will show your gravatar)


Copyright © Jason Olson | Powered by: GeeksWithBlogs.net