TPL : Build your own TPL for Silverlight, WP7 and XBox 360

This blog is a translation of https://blogs.msdn.com/b/eternalcoding/archive/2011/05/16/fr-sous-le-capot-etude-de-la-task-parallel-library.aspx

With this post, we will discover the Task Parallel Library (a library to simply manage your parallel developments with the .Net framework 4.0). But we will do this in a slightly different way. Indeed, we will totally rewrite it from scratch Sourire.

Of course, we will not do as well as the original TPL. We will focus on key concepts in order to understand how the TPL works.

We shall take advantage of writing our version to make it usable with multiple frameworks. To do that, we only need to install the Portable Library Tools. Once the latter installed, a new project appears in Visual Studio that will allow us to develop our TPL:

image_thumb[1]

With this project type, we will develop an assembly usable with .Net 4.0, Silverlight 4 (and 5), Silverlight for Windows Phone 7 and even with XNA 4.0 for XBox 360 !

Of course, this portability will have a price in terms of functionalities.

You can already download the Portable TPL just here : https://portabletpl.codeplex.com.

You can also install it with a NuGet package : https://www.nuget.org/List/Packages/PortableTPL.

However before writing our code, we will study the original TPL to see how we can build our solution.

Task & TaskFactory

TPL is built on a class called Task which is an unity of work to realize.

It is like a ThreadPool.QueueUserWorkItem(). So to realize a work, just create a Task with the action to realize in parameter :





var task = new Task(state =>
{
foreach (int value in data)
{
Thread.Sleep(value
* (int)state);
}
},
100);
task.Start();
task.Wait();




<p>
  Another solution to start a Task is to use the TaskFactory.StartNew() method which is on the static class Task.Factory :
</p>

<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:ad999d03-595f-401e-b80c-8c66bc35bec6" class="class">
  <pre style="background-color: white; width: 789px; height: 123px; overflow: auto"><div>

Task task = Task.Factory.StartNew(() =>
{
foreach (int value in data)
{

}
});
task.Wait();

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    We can remark the use of Task.Wait() which allows the synchronization between the task and our current thread.
  </p>

  <p>
    In addition, you need to know there is another class for tasks: Task<T>. This daughter of Task&#160; adds the concept of return value:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:88b9afc0-56a5-41d2-be32-4e6e43dfc918" class="class">
    <pre style="background-color: white; width: 789px; height: 197px; overflow: auto"><div>

Task<int> task = Task.Factory.StartNew<int>(
(limit)
=>
{
int sum = ;
for (int i = ; i < (int)limit; i++)
{
sum
+= i;
}
return sum;
},
100);
task.Wait();
Console.WriteLine(task.Result);

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    Thus Task<T> is designed to retrieve a result where Task executes only an action.
  </p>

  <h1>
    Task continuation
  </h1>

  <p>
    Task continuation is another feature we will cover with our solution. Indeed, the task continuation allows the launch of a secondary task when a primary one is terminated.
  </p>

  <p>
    To do so, we only need to use the ContinueWith() method:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:3df6fae9-5f20-4728-bea7-cc96432e4acd" class="class">
    <pre style="background-color: white; width: 789px; height: 172px; overflow: auto"><div>

Task task = Task.Factory.StartNew(() =>
{
foreach (int value in data)
{

}
});
task.ContinueWith(t
=>
{
// Code de la seconde tâche…
});

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    The secondary task will receive the primary task in parameter in order to process errors (if any).
  </p>

  <h1>
    Schedulers and work stealing
  </h1>

  <p>
    The tasks are managed and organized by schedulers whose role is to dispatch them on worker threads. Indeed, according to the number of processors, TPL will create the right count of working threads. Each task to run would be then treated by one of these worker threads.
  </p>

  <p>
    The allocation of tasks on the worker threads will be made according to different algorithms. In our case we will cover the standard scheduler (which distributes the workload in a uniform manner) and the scheduler of the synchronization context (where all tasks run on the UI thread to allow them to drive the interface).
  </p>

  <p>
    Thus, schedulers each have a queue of the tasks assigned to them.
  </p>

  <p>
    In addition, the TPL handles additional functionality: the work stealing. Indeed, if a worker thread has an empty queue and his colleagues still have work to do, it will gently steal a portion of their remaining work. All of this is done to ensure a constant distribution of the load on each processor.
  </p>

  <p>
    By default, the tasks are launched on the standard scheduler. However if you want to start a task on the scheduler of the synchronization context, you simply need to execute this code:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:fbe17086-e227-4fdb-98e6-25224b011731" class="class">
    <pre style="background-color: white; width: 789px; height: 129px; overflow: auto"><div>

Task task = Task.Factory.StartNew(() =>
{
foreach (int value in data)
{
Thread.Sleep(value
* 100);
}
},CancellationToken.None,
TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    A sample of the use of this type of continuation can be the update of an interface after the execution of a task. Before the launch of the task we can display an hourglass or a wait animation and then start our task. When the task completes, on a second task running on the scheduler of the synchronization context and in continuation of the first we can hide our control to indicate to the user the end of the treatment.
  </p>

  <h1>
    State management
  </h1>

  <p>
    Tasks have a status property to indicate their current state :
  </p>

  <ul>
    <li>
      <strong>TaskStatus.Created</strong> : First state of a task. Task is not yet launched or even scheduled.
    </li>
    <li>
      <strong>TaskStatus.WaitingForActivation</strong> : Task was launched but is not yet assigned to a worker thread by a scheduler.
    </li>
    <li>
      <strong>TaskStatus.WaitingToRun</strong> : Task was assigned to a worker thread but is not yet executed.
    </li>
    <li>
      <strong>TaskStatus.Running</strong> : Task is executed by a worker thread.
    </li>
    <li>
      <strong>TaskStatus.RanToCompletion</strong> : Everything is ok!!! The task was executed successfully.
    </li>
    <li>
      <strong>TaskStatus.Faulted</strong> : An exception was thrown.
    </li>
    <li>
      <strong>TaskStatus.Canceled</strong> : User has cancelled the execution of the task.
    </li>
  </ul>

  <p>
    So we can follow the complete life of the task through its status.
  </p>

  <p>
    In addition, tasks have several properties that bring together some status:
  </p>

  <ul>
    <li>
      <strong>Task.IsCanceled</strong> : Like Status == Canceled
    </li>
    <li>
      <strong>Task.IsFaulted</strong> : Like Status == Faulted
    </li>
    <li>
      <strong>Task.IsCompleted</strong> : Like Status == RanToCompletion or Faulted or Canceled
    </li>
  </ul>

  <h1>
    Cancellation
  </h1>

  <p>
    TPL allows the developer to simply manage the concept of cancellation within the tasks. Indeed, since the framework.NET 4.0, the CancellationTokenSource class has been added to serve as a basis for cancellation. In the TPL, this class will emit a token that will be copied to the task. It allows to know if a cancel has been requested at the level of the CancellationTokenSource class. If this is the case, the token can throw a cancellation exception:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:823a7de3-516a-4e98-90b0-be99f8a9fe81" class="class">
    <pre style="background-color: white; width: 789px; height: 248px; overflow: auto"><div>

var tokenSource = new CancellationTokenSource();
var token
= tokenSource.Token;

var task = Task.Factory.StartNew(limit =>
{
for (int i = ; i < (int)limit; i++)
{
token.ThrowIfCancellationRequested();
Console.WriteLine(
Processing {0}, i);
}
},
2000, token);

Thread.Sleep(200);

Console.WriteLine(Let’s cut…);
tokenSource.Cancel();

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    We can of course make the choice to not throw an exception but rather to quit the task if we detect the token&#8217;s IsCancellationRequested property set to True.
  </p>

  <p>
    The launch of the cancellation is done on the CancellationTokenSource that issued tokens. This can cancel several tasks at once. It is even possible to register with the token via the Register method to be notified when a cancellation is requested.
  </p>

  <h1>
    The Parallel class
  </h1>

  <p>
    In addition to the notion of tasks, TPL adds support for Parallel class which will allow us to do parallel loops in a really elegant way:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:8d183e4e-df49-497d-87fc-ba2ed0fdb0cb" class="class">
    <pre style="background-color: white; width: 789px; height: 72px; overflow: auto"><div>

Parallel.For(, 10, i =>
{
Console.WriteLine(i);
});

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    The same thing with ForEach :
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:0dcacf47-bb1c-47af-8154-b24c044fe8ea" class="class">
    <pre style="background-color: white; width: 789px; height: 27px; overflow: auto"><div>

Parallel.ForEach(new[]{toto, titi}, Console.WriteLine);

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    Of course, with the use of these methods, we must be careful that each loop is really independent to not cause cross-threads access violations.
  </p>

  <h1>
    Exception handling
  </h1>

  <p>
    TPL offers an elegant solution for the management of exceptions. Indeed, if in the body of a task, an exception should be thrown, TPL will catch it for us.
  </p>

  <p>
    It will be subsequently transmitted to the user when:
  </p>

  <ul>
    <li>
      Parallel.For/ForEach returns
    </li>
    <li>
      Calling the Wait method of a Task
    </li>
    <li>
      Calling the Result property of Task <T>.
    </li>
  </ul>

  <p>
    The important point to note here is that TPL will aggregate the exceptions that might occur in a task or a Parallel.For/ForEach to present them on the calling thread:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:8cfc5a73-c77c-489e-9ade-a91bfa875b55" class="class">
    <pre style="background-color: white; width: 789px; height: 280px; overflow: auto"><div>

try
{
Parallel.For(
, 10, i =>
{
Console.WriteLine(i);
if (i == 5)
throw new Exception(erf…);
});
}
catch (AggregateException aggEx)
{
foreach (Exception ex in aggEx.InnerExceptions)
{
Console.WriteLine(
string.Format(Caught exception ‘{0}’, ex.Message));
}
}
Console.ReadLine();

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    In this sample, the system write 10 values to the console and then at the exit of the Parallel.For, TPL threw the aggregate exception. We will therefore see appear the superb "caught exception erf…" message.
  </p>

  <p>
    In the same way, we can retrieve the exception on a Task.Wait:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:9a927005-5178-4930-a332-5448a9614ad2" class="class">
    <pre style="background-color: white; width: 789px; height: 369px; overflow: auto"><div>

Task<int> task = Task.Factory.StartNew(
limit
=>
{
int sum = ;
for (int i = ; i < (int)limit; i++)
{
sum
+= i;
if (i == 12)
throw new Exception(Bad trip…);
}
return sum;
},
100);
try
{
task.Wait();
Console.WriteLine(task.Result);
}
catch (AggregateException aggregateException)
{
foreach (Exception ex in aggregateException.InnerExceptions)
{
Console.WriteLine(
string.Format(Caught exception ‘{0}’, ex.Message));
}
}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    If we do not call a method or a property that throws the aggregation exception, then the latter will not be observed. The only way then to know if an error has actually occurred will be watching the value of Task.Status or Task.IsFaulted.
  </p>

  <h1>
    Our architecture
  </h1>

  <p>
    It is therefore now that serious things start! We know what we are talking about, we have the vocabulary, we are now ready to reproduce the same thing with our framework limited by the Portable Library.
  </p>

  <p>
    And foremost, here is our class diagram:
  </p>

  <p>
    <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/44/73/metablogapi/2148.image_thumb3_57C43D4B.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-73-metablogapi/2148.image_5F00_thumb3_5F00_57C43D4B.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image_thumb3" border="0" alt="image_thumb3" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/44/73/metablogapi/2664.image_thumb3_thumb_69542816.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-73-metablogapi/2664.image_5F00_thumb3_5F00_thumb_5F00_69542816.png" width="650" height="374" /></a>
  </p>

  <h1>
    Implementation
  </h1>

  <p>
    As a reminder, the current solution is certainly not the true TPL and is only intended to be <u><strong>educational</strong></u>.
  </p>

  <h1>
  </h1>

  <h2>
    Worker threads
  </h2>

  <p>
    The worker threads are THE real workers in our case. They go to the mine to perform tasks. Work is assigned to them by the schedulers.
  </p>

  <p>
    Internally, they have a queue (that must be protected against concurrent access by using locks) of tasks. Their main loop is built around a ManualResetEvent (that will be signaled as soon as a new task is added) :
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:8e0e3de1-aa06-4f04-a1b6-965bbef210c4" class="class">
    <pre style="background-color: white; width: 789px; height: 342px; overflow: auto"><div>

internal void AddTask(Task task)
{
task.SetIsScheduled();

</span><span style="color: #0000ff">lock</span><span style="color: #000000"> (workQueue)
{
    workQueue.Enqueue(task);
}
workEvent.Set();

}

internal void AddTasks(Task[] tasks)
{
lock (workQueue)
{
foreach (Task task in tasks)
{
workQueue.Enqueue(task);
}
}
workEvent.Set();
}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    The main work loop will therefore wait passively on the ManualResetEvent and later will process its queue until it is empty:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:f9080579-1199-4366-b3cc-eed1394bd68f" class="class">
    <pre style="background-color: white; width: 789px; height: 475px; overflow: auto"><div>

void ThreadJob()
{
while (true)
{
workEvent.WaitOne();
workEvent.Reset();

    </span><span style="color: #0000ff">if</span><span style="color: #000000"> (quitCondition)
        </span><span style="color: #0000ff">return</span><span style="color: #000000">;

    Task task;
    </span><span style="color: #0000ff">bool</span><span style="color: #000000"> noWork </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #0000ff">false</span><span style="color: #000000">;

    </span><span style="color: #0000ff">do</span><span style="color: #000000">
    {
        </span><span style="color: #0000ff">bool</span><span style="color: #000000"> emptyQueue </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">!</span><span style="color: #000000">workQueue.TryDequeue(</span><span style="color: #0000ff">out</span><span style="color: #000000"> task);

        </span><span style="color: #0000ff">if</span><span style="color: #000000"> (emptyQueue </span><span style="color: #000000">&&</span><span style="color: #000000"> </span><span style="color: #000000">!</span><span style="color: #000000">scheduler.StealWork(</span><span style="color: #0000ff">this</span><span style="color: #000000">))
        {
            noWork </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #0000ff">true</span><span style="color: #000000">;
        }

        </span><span style="color: #0000ff">if</span><span style="color: #000000"> (task </span><span style="color: #000000">!=</span><span style="color: #000000"> </span><span style="color: #0000ff">null</span><span style="color: #000000">)
            task.DoWork();

        </span><span style="color: #0000ff">if</span><span style="color: #000000"> (quitCondition)
            </span><span style="color: #0000ff">return</span><span style="color: #000000">;

    }
    </span><span style="color: #0000ff">while</span><span style="color: #000000"> (</span><span style="color: #000000">!</span><span style="color: #000000">noWork);
}

}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    Here we can see the presence of a condition of output (QuitCondition) and the work stealing algorithm (scheduler.StealWork) that we will see later.
  </p>

  <p>
    The task (in order to run its code) provides a DoWork method that calls the delegate defined in its constructor:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:c5dfb89e-fc3c-40ea-a2cc-7dfd75652ff1" class="class">
    <pre style="background-color: white; width: 789px; height: 117px; overflow: auto"><div>

protected virtual void ExecuteDelegate()
{
if (ActionDelegate.Method.GetParameters().Length > )
ActionDelegate.DynamicInvoke(AsyncState);
else
ActionDelegate.DynamicInvoke();
}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <h2>
    Schedulers
  </h2>

  <p>
    A scheduler must at least provide an EnqueueTask method to add a new task to its list of tasks to dispatch on its worker threads.
  </p>

  <p>
    Thus, we have an abstract TaskScheduler class to define this behavior.
  </p>

  <p>
    In addition this class will have a static property ProcessorCount that must be defined by the user. Indeed, the Portable Library prevents us to access Environment.ProcessorCount because the latter is not present on all the targeted frameworks.
  </p>

  <h3>
    Standard Scheduler
  </h3>

  <p>
    It is the main scheduler. It allocates a number of worker threads equal to the number of processors defined by the TaskScheduler.ProcessorCount property.
  </p>

  <p>
    To implement the EnqueueTask method, the scheduler will look for the worker thread whose work queue is the smallest:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:d8e1590b-e961-438b-95d7-fc8e3dce8296" class="class">
    <pre style="background-color: white; width: 789px; height: 247px; overflow: auto"><div>

WorkerThread FindLowestQueue()
{
WorkerThread result
= null;
int currentLevel = int.MaxValue;

</span><span style="color: #0000ff">foreach</span><span style="color: #000000"> (WorkerThread workerThread </span><span style="color: #0000ff">in</span><span style="color: #000000"> workerThreads)
{
    </span><span style="color: #0000ff">if</span><span style="color: #000000"> (workerThread.QueueLength </span><span style="color: #000000">&lt;</span><span style="color: #000000"> currentLevel)
    {
        currentLevel </span><span style="color: #000000">=</span><span style="color: #000000"> workerThread.QueueLength;
        result </span><span style="color: #000000">=</span><span style="color: #000000"> workerThread;
    }
}

</span><span style="color: #0000ff">return</span><span style="color: #000000"> result;

}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    Once a worker thread is found, the scheduler will just add it the task to execute.
  </p>

  <h3>
    Synchronization context scheduler
  </h3>

  <p>
    This scheduler is quite simple since it sends all its tasks on the synchronization context (for instance the Dispatcher for WPF):
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:c0e98a26-fe3d-4149-895b-5438c887a31c" class="class">
    <pre style="background-color: white; width: 789px; height: 65px; overflow: auto"><div>

public override void EnqueueTask(Task task)
{
context.Post(state
=> task.DoWork(), null);
}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    This scheduler is built by a static method of the TaskScheduler class:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:1f70e950-fca3-4adc-82b2-639225ee50db" class="class">
    <pre style="background-color: white; width: 789px; height: 79px; overflow: auto"><div>

public static TaskScheduler FromCurrentSynchronizationContext()
{
return new SynchronisationContextTaskScheduler(SynchronizationContext.Current);
}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <h2>
    Work stealing
  </h2>

  <p>
    As we have seen above, the scheduler can balance the load of worker threads by moving tasks for one worker thread to another.
  </p>

  <p>
    So the StealWork method is :
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:00f73084-009e-4726-be21-2642046c2f8b" class="class">
    <pre style="background-color: white; width: 789px; height: 411px; overflow: auto"><div>

internal bool StealWork(WorkerThread source)
{
foreach (WorkerThread workerThread in workerThreads)
{
if (workerThread == source)
continue;

    </span><span style="color: #0000ff">if</span><span style="color: #000000"> (workerThread.QueueLength </span><span style="color: #000000">&gt;</span><span style="color: #000000"> </span><span style="color: #800080">1</span><span style="color: #000000">)
    {
        </span><span style="color: #0000ff">int</span><span style="color: #000000"> total </span><span style="color: #000000">=</span><span style="color: #000000"> workerThread.QueueLength </span><span style="color: #000000">/</span><span style="color: #000000"> </span><span style="color: #800080">2</span><span style="color: #000000">;
        List</span><span style="color: #000000">&lt;</span><span style="color: #000000">Task</span><span style="color: #000000">&gt;</span><span style="color: #000000"> stolenWork </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #0000ff">new</span><span style="color: #000000"> List</span><span style="color: #000000">&lt;</span><span style="color: #000000">Task</span><span style="color: #000000">&gt;</span><span style="color: #000000">();
        </span><span style="color: #0000ff">for</span><span style="color: #000000"> (</span><span style="color: #0000ff">int</span><span style="color: #000000"> index </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #800080"></span><span style="color: #000000">; index </span><span style="color: #000000">&lt;</span><span style="color: #000000"> total; index</span><span style="color: #000000">++</span><span style="color: #000000">)
        {
            Task task;
            </span><span style="color: #0000ff">if</span><span style="color: #000000"> (workerThread.TryDequeue(</span><span style="color: #0000ff">out</span><span style="color: #000000"> task))
            {
                stolenWork.Add(task);
            }
        }

        source.AddTasks(stolenWork.ToArray());
        </span><span style="color: #0000ff">return</span><span style="color: #000000"> </span><span style="color: #0000ff">true</span><span style="color: #000000">;
    }
}

</span><span style="color: #0000ff">return</span><span style="color: #000000"> </span><span style="color: #0000ff">false</span><span style="color: #000000">;

}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    It iterates through the list of the worker threads and as soon as it finds one that still has work (more than a task), it will"steals" half of his work.
  </p>

  <h2>
    The Parallel Class
  </h2>

  <p>
    The static class Parallel is finally an different entry point to generate tasks. Indeed, Parallel will appeal to the services of a standard scheduler which will execute the following code :
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:720999f6-9f40-4702-b754-698968f0d73b" class="class">
    <pre style="background-color: white; width: 789px; height: 442px; overflow: auto"><div>

void Dispatch(int stackSize, int excludedEnd, Func<int, Task> produceTask)
{
List
<Task> totalTasks = new List<Task>();

</span><span style="color: #0000ff">int</span><span style="color: #000000"> index </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #800080"></span><span style="color: #000000">;
</span><span style="color: #0000ff">foreach</span><span style="color: #000000"> (WorkerThread workerThread </span><span style="color: #0000ff">in</span><span style="color: #000000"> workerThreads)
{
    </span><span style="color: #0000ff">int</span><span style="color: #000000"> start </span><span style="color: #000000">=</span><span style="color: #000000"> index </span><span style="color: #000000">*</span><span style="color: #000000"> stackSize;
    </span><span style="color: #0000ff">int</span><span style="color: #000000"> end </span><span style="color: #000000">=</span><span style="color: #000000"> start </span><span style="color: #000000">+</span><span style="color: #000000"> stackSize;

    </span><span style="color: #0000ff">if</span><span style="color: #000000"> (index </span><span style="color: #000000">==</span><span style="color: #000000"> ProcessorCount </span><span style="color: #000000">-</span><span style="color: #000000"> </span><span style="color: #800080">1</span><span style="color: #000000">)
        end </span><span style="color: #000000">=</span><span style="color: #000000"> excludedEnd;

    Task[] tasks </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #0000ff">new</span><span style="color: #000000"> Task[end </span><span style="color: #000000">-</span><span style="color: #000000"> start];
    </span><span style="color: #0000ff">int</span><span style="color: #000000"> taskID </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #800080"></span><span style="color: #000000">;

    </span><span style="color: #0000ff">for</span><span style="color: #000000"> (</span><span style="color: #0000ff">int</span><span style="color: #000000"> local </span><span style="color: #000000">=</span><span style="color: #000000"> start; local </span><span style="color: #000000">&lt;</span><span style="color: #000000"> end; local</span><span style="color: #000000">++</span><span style="color: #000000">)
    {
        Task task </span><span style="color: #000000">=</span><span style="color: #000000"> produceTask(local);
        tasks[taskID</span><span style="color: #000000">++</span><span style="color: #000000">] </span><span style="color: #000000">=</span><span style="color: #000000"> task;
    }

    totalTasks.AddRange(tasks);
    workerThread.AddTasks(tasks);
    index</span><span style="color: #000000">++</span><span style="color: #000000">;
}

Task.WaitAll(totalTasks.ToArray());

}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    In this method, we divide the number of items to be treated by the number of worker threads available. A bunch of tasks are then created and we just have to wait for their completion.
  </p>

  <h2>
    Exception handling
  </h2>

  <p>
    The management of exceptions will happen at the level of the tasks. We must protect the call to the delegate of a task by using a try/catch block. We must then take the encapsulated exception and store it in our aggregate exception:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:a8924f0a-175d-4d54-98f4-4f622f31e225" class="class">
    <pre style="background-color: white; width: 789px; height: 275px; overflow: auto"><div>

try
{
ExecuteDelegate();
}
catch (TargetInvocationException exception)
{
if (aggregateException == null)
{
aggregateException
= new AggregateException();
}

aggregateException.InnerExceptions.Add(exception.InnerException);
status </span><span style="color: #000000">=</span><span style="color: #000000"> TaskStatus.Faulted;  


</span><span style="color: #0000ff">return</span><span style="color: #000000">;

}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <h2>
    Cancellation
  </h2>

  <p>
    Cancellation management is done through a CancellationToken that will throw an exception if there is a cancellation request:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:5b3ee2ba-d273-467f-b82d-59f02d84510e" class="class">
    <pre style="background-color: white; width: 789px; height: 110px; overflow: auto"><div>

public void ThrowIfCancellationRequested()
{
if (isCancellationRequested)
{
throw new OperationCanceledException(this);
}
}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    Later, we will have to change our management of exceptions to a different behavior when an exception of type OperationCanceledException is thrown:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:1ef013aa-83d6-44e8-97e6-cdb8c657752d" class="class">
    <pre style="background-color: white; width: 789px; height: 401px; overflow: auto"><div>

try
{
WaitEvent.Reset();
ExecuteDelegate();
}
catch (TargetInvocationException exception)
{
if (aggregateException == null)
{
aggregateException
= new AggregateException();
}

</span><span style="color: #0000ff">if</span><span style="color: #000000"> (exception.InnerException </span><span style="color: #0000ff">is</span><span style="color: #000000"> OperationCanceledException)
{
    aggregateException.InnerExceptions.Add(</span><span style="color: #0000ff">new</span><span style="color: #000000"> TaskCanceledException());
}

</span><span style="color: #0000ff">if</span><span style="color: #000000"> (status </span><span style="color: #000000">!=</span><span style="color: #000000"> TaskStatus.Canceled)
{
    aggregateException.InnerExceptions.Add(exception.InnerException);
    status </span><span style="color: #000000">=</span><span style="color: #000000"> TaskStatus.Faulted;  
}


</span><span style="color: #0000ff">return</span><span style="color: #000000">;

}

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    Thus, if we encounter a cancellation at the level of exceptions, we must not setting the status to Faulted because the task will set it to Canceled.
  </p>

  <h1>
    Results & benchmarks
  </h1>

  <p>
    Just for fun, I tried to replace TPL in my own raytracer (Bolas) code. Indeed, through a Parallel.For, I treat each line of my image in parallel to speed up the final rendering:
  </p>

  <p>
    <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/44/73/metablogapi/1018.image_thumb1_10CAF481.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-73-metablogapi/1018.image_5F00_thumb1_5F00_10CAF481.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image_thumb1" border="0" alt="image_thumb1" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/44/73/metablogapi/0363.image_thumb1_thumb_7E7207F1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-44-73-metablogapi/0363.image_5F00_thumb1_5F00_thumb_5F00_7E7207F1.png" width="604" height="422" /></a>
  </p>

  <p>
    The relevant code is the following:
  </p>

  <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:da20e6e5-0c6a-410f-91c9-ad87b2f16957" class="class">
    <pre style="background-color: white; width: 789px; height: 211px; overflow: auto"><div>

Task task = Task.Factory.StartNew(() =>
{
if (scene == null || scene.Camera == null)
return;
if (IsParallel)
{
Parallel.For(
, RenderHeight, y => ProcessLine(scene, y));
return;
}
for (int y = ; y < RenderHeight; y++)
{
ProcessLine(scene, y);
}
});

<p>
  <!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  https://dunnhq.com --></div> 

  <p>
    As you can see, it is a simple Parallel.For which calls the ProcessLine method for each row.
  </p>

  <p>
    Using the TPL, an image of 800 x 800 with anti-aliasing required 47s to generate.
  </p>

  <p>
    By using our version, it takes 45s to generate the same image. The result is therefore quite acceptable.
  </p>

  <p>
    Then of course, TPL is far better both in terms of stability and reliability and adds many other features.<br />
  </p>

  <p>
    But what it is important to understand here is that there is no magic. By understanding how the TPL works, you will be able to better architect your code by taking the right decisions in terms of parallel management design.
  </p>