Thursday, December 23, 2010

WPF - Thread Synchronization using Barrier

In this post, we will be discussing about a new Thread Signaling construct available in .net 4.0. This signaling construct is Barrier. It basically allows participating threads to work in phases in synchronization. After signaling, the barrier blocks the threads from execution until all participating threads have signaled. As all signals are received, it performs a post-blocking action. As soon as the post-blocking action is finished, all participating threads can resume their operation.

We discussed CountdownEvent in the previous post. It must be remembered that both of these signaling constructs are introduced with .net 4.0. Though CountdownEvent also depends upon signaling of a certain number of threads but it does not block them after they signal until we explicitly call Wait afterwards [http://msdn.microsoft.com/en-us/library/system.threading.countdownevent.wait.aspx]. The other difference is that a thread can only signal once at one time for barrer. Alternatively, CountdownEvent can generate two signals by using overloads of Signal method available.

This seems to be very disciplined construct. The example of this feature should be form an environment which is also very disciplined. Let us take the example of an army mission. A team of 4 army-men are formed to attack an enemy land. The team consists of three soldiers and their commander. Each soldier has to secure a position and signal the commander. When all soldiers have signaled, the commander runs all procedures and orders the attack. In order to keep the example simple, we are discussing this one phase, otherwise, we can also extend this example for other posts in the enemy land. We can also update it to include the provision of reducing the number of participants when a soldier is down.



The form should appear as follows:



Clicking each button should update the display about the ready position of the soldier. When all buttons are clicked, the commander notification text box is udpated as "Attack!!!".

This window is designed as follows:

<Window x:Class="WpfApplication_Barrier.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="T1 ready to attack" Height="31" HorizontalAlignment="Left" Margin="16,53,0,0"
Name="btnT1" VerticalAlignment="Top" Width="156" Click="btnT1_Click" />
<Button Content="T2 ready to attack" Height="31" HorizontalAlignment="Left" Margin="16,100,0,0"
Name="btnT2" VerticalAlignment="Top" Width="156" Click="btnT2_Click" />
<Button Content="T3 ready to attack" Height="31" HorizontalAlignment="Left" Margin="16,144,0,0"
Name="btnT3" VerticalAlignment="Top" Width="156" Click="btnT3_Click" />
<TextBlock Height="46" HorizontalAlignment="Left" Margin="260,24,0,0"
Name="txtNotificationCommander" Text="Commander Waiting..." VerticalAlignment="Top" Width="231" />
<TextBlock Height="29" HorizontalAlignment="Left" Margin="197,55,0,0"
Name="textBlockT1AttackNotification" Text="" VerticalAlignment="Top" Width="194" />
<TextBlock Height="25" HorizontalAlignment="Left" Margin="197,100,0,0" Name="textBlockT2AttackNotification"
Text="" VerticalAlignment="Top" Width="196" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="194,152,0,0" Name="textBlockT3AttackNotification"
Text="" VerticalAlignment="Top" Width="201" />
</Grid>
</Window>

The code behind of the window is as follows:

public partial class MainWindow : Window
{
static Barrier _barrier;
public MainWindow()
{
InitializeComponent();

_barrier = new Barrier(3, (a) =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.txtNotificationCommander.Text = "Running SOP for attack..."));

Thread.Sleep(5000);

this.Dispatcher.BeginInvoke(new Action(() =>
this.txtNotificationCommander.Text = "Attack!!!"));
}
);

}

private void btnT1_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT1AttackNotification.Text = "T1 ready Sir!"));

_barrier.SignalAndWait();

this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT1AttackNotification.Text = "T1 attacks!"));
}
).Start();
}

private void btnT3_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT3AttackNotification.Text = "T3 ready Sir!"));

_barrier.SignalAndWait();

this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT3AttackNotification.Text = "T3 attacks!"));
}
).Start();
}

private void btnT2_Click(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT2AttackNotification.Text = "T2 ready Sir!"));
_barrier.SignalAndWait();

this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT2AttackNotification.Text = "T2 attacks!"));
}
).Start();

}
}

When we click button 1, a signal is generated by T1. The thread is blocked after this until barrier allows it.
new Thread(() =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT1AttackNotification.Text = "T1 ready Sir!"));

_barrier.SignalAndWait();

this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT1AttackNotification.Text = "T1 attacks!"));
}
).Start();



Now click the second button. This would cause T2 to start blocking.

new Thread(() =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT2AttackNotification.Text = "T2 ready Sir!"));
_barrier.SignalAndWait();

this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT2AttackNotification.Text = "T2 attacks!"));
}
).Start();



Now click third button. This would create a new thread and signal the barrier.

new Thread(() =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT3AttackNotification.Text = "T3 ready Sir!"));

_barrier.SignalAndWait();

this.Dispatcher.BeginInvoke(new Action(() =>
this.textBlockT3AttackNotification.Text = "T3 attacks!"));
}
).Start();



Now look at the definition of barrier, _barrier. Since all signals are received, it can run the post-phase action. In this case, we are just using Thread.Sleep() to simulate any work done by the thread.

_barrier = new Barrier(3, (a) =>
{
this.Dispatcher.BeginInvoke(new Action(() =>
this.txtNotificationCommander.Text = "Running SOP for attack..."));

Thread.Sleep(5000);

this.Dispatcher.BeginInvoke(new Action(() =>
this.txtNotificationCommander.Text = "Attack!!!"));
}
);



The form is updated as follows:



When the action is finished execution, all threads are signaled to unblock themselves. In our example, they just update the form with new text.





You can see that how easily we have implemented this complex logic which involved the working of a bunch of threads in synchronization.

No comments: