Silverlight Sorting Lab
Written by Ian Elliot   
Tuesday, 12 October 2010
Article Index
Silverlight Sorting Lab
Shuffle
Bubble sort
Synchronization
Reducing bubble, shaker and shell
Speedy Quicksort

 

Banner

Synchronization Context

You need the Thread.Sleep(1) to yield to the UI thread so that it can process the dispatch queue. Without it everything hangs.

Of course if they UI thread can't get the job done in 1 millisecond then the whole thing will hang once again. This isn't very satisfactory. It would be better to use the blocking Invoke method which would cause the worker thread to suspend until the UI thread had completed the Invoked method. However we can't use Invoke because Silverlight 4.0 doesn't support this WPF method.

Not only doesn't the Silverlight 4.0 Dispatcher support Invoke it really doesn't have the methods necessary to allow you to control what is happening to the dispatch queue and trying to create the equivalent of an Invoke command is difficult

An alternative approach is to make use of relatively new DispatcherSynchronizationContext class. This provides two important methods - Post and Send. Post is equivalent to BeginInvoke i.e. it is asynchronous and Send is equivalent to Invoke i.e. it is synchronous. The delgates which are run are always run on a dispatcher's thread - this is what makes DispatcherSynchronizationContext different from the general SynchronizationContext class.

To see this in action all we have to do is modify code from the BeginInvoke to read:

DispatcherSynchronizationContext 
   context = new
     DispatcherSynchronizationContext();
context.Send((object state) =>
  {
   int i1 = ((swapindex)state).i;
   int j1 = ((swapindex)state).j;
   double temp;
   temp = lines[i1].X2;
   lines[i1].X2 = lines[j1].X2;
   lines[j1].X2 = temp;
},
 new swapindex() { i = i, j = j });
}

There is form of the constructor that allows you to specify which dispatcher the synchronization context is created using but in most cases there is only one dispatcher and you can assume that it is the current i.e. default dispatcher.

Notice that the parameters passed to the lambda have to be packaged up into an object. Of course we don't have to do this because the lambda expression can access the i and j variables directly making use of closure. That is:

DispatcherSynchronizationContext 
 context =
  new DispatcherSynchronizationContext();
context.Send((object state) =>
 {
  double temp;
  temp = lines[i].X2;
  lines[i].X2 = lines[j].X2;
  lines[j].X2 = temp;
 }, new object());
}

If you run the program now and try out the Bubble sort you will notice that it runs slower than the version with BeginInvoke. The reason for this is that the BeginInvoke version puts multiple updates on the dispatcher's queue before the UI thread gets to process them. The Send version waits for the UI Thread to display the change before continuing and is slower.However this is the only way that is guaranteed never to over-run the UI thread and cause it to lock.

More bubbles

So far the going has been tough but now we have a swap method that does the job the rest is comparatively easy. We can now implement the two variations on the bubble sort without worrying about threads - well after we have extended the sort selection routine:

private void button3_Click(object sender,
                      RoutedEventArgs e)
{
if (Working) return;
Working = true;
if ((bool)radioButton1.IsChecked)
{
  Thread T1 = new Thread(
         new ThreadStart(BubbleSimple));
  T1.Start();
}
if ((bool)radioButton2.IsChecked)
{
  Thread T1 = new Thread(
          new ThreadStart(BubbleReduc));
  T1.Start();
}
if ((bool)radioButton3.IsChecked)
{
  Thread T1 = new Thread(
             new ThreadStart(BubbleBi));
  T1.Start();
}

As we have already implemented the simple bubble sort all we have to do now is implement the reducing and bi-directional versions.

 

Banner

<ASIN:1430224819>

<ASIN:0470477229>

<ASIN:1430272058>

<ASIN:1430272406>

<ASIN:1430225394>



Last Updated ( Monday, 30 October 2023 )