<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Parallel Programming with .NET : Coordination Data Structures</title><link>http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx</link><description>Tags: Coordination Data Structures</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Slides from Parallelism Tour</title><link>http://blogs.msdn.com/pfxteam/archive/2009/11/01/9916008.aspx</link><pubDate>Mon, 02 Nov 2009 02:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9916008</guid><dc:creator>toub</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9916008.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9916008</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9916008</wfw:comment><description>&lt;P&gt;Last week, I had the privilege of touring around Tennessee, Kentucky, Ohio, and Michigan, speaking about the new parallel computing support in Visual Studio 2010 and the .NET Framework 4.&amp;nbsp; Many folks I spoke with were interested in getting a copy of the slide deck I used, so I’ve attached it to this blog post.&amp;nbsp; Enjoy!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9916008" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pfxteam/attachment/9916008.ashx" length="2231000" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Talks/default.aspx">Talks</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Visual+Studio+2010/default.aspx">Visual Studio 2010</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4/default.aspx">.NET 4</category></item><item><title>Cancellation in Parallel Extensions</title><link>http://blogs.msdn.com/pfxteam/archive/2009/06/22/9791840.aspx</link><pubDate>Mon, 22 Jun 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9791840</guid><dc:creator>mikelid</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9791840.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9791840</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9791840</wfw:comment><description>&lt;P&gt;One of the great features that crosses all of Parallel Extensions types is a consistent approach to cancellation (see &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx"&gt;http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx&lt;/A&gt;). In this post we explore some of the ways cancellation is used in Parallel Extensions and explain the guidance we developed. &lt;/P&gt;
&lt;P&gt;The new cancellation system is a cooperative approach based on two new types: CancellationTokenSource, which initiates cancellation requests, and CancellationToken which communicates a cancellation request to asynchronous operations and to long-running and blocking method calls.&lt;/P&gt;
&lt;P&gt;If you are experimenting with Parallel Extensions, you might like to keep an eye out for the methods that accept a CancellationToken and test them out. &lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Blocking calls&lt;/H3&gt;
&lt;P&gt;Some of the Parallel Extension types introduce blocking methods, for example BlockingCollection.Take() and Task.Wait(). The default overloads for these methods will block indefinitely if the condition they are waiting for never occurs. One solution used by these APIs, and many others like them, is to provide a timeout overload so that they may return after some duration and report that the condition did not occur. However, a timeout isn't particularly convenient if you only want to stop waiting if a specific activity occurs, such as a user clicking a 'cancel' button. One possibility is to wait for some amount of time such as 100 milliseconds, check if the button was pressed, and if not then go back to waiting, but this puts the burden on the call-site and must be re-implemented repeatedly; and depending on the frequency of the polling, it may also add unnecessary cost. The types in Parallel Extensions use the new cancellation system and provide overloads that accept a CancellationToken which can cause early termination of blocking methods in response to a specific cancellation request.&lt;/P&gt;
&lt;P&gt;Here are some examples of the blocking calls in Parallel Extensions that accept a CancellationToken:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;BlockingCollection: &lt;BR&gt;&lt;/STRONG&gt;void Add(T item, CancellationToken cancellationToken) &lt;BR&gt;T Take(CancellationToken cancellationToken)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;ManualResetEventSlim: &lt;BR&gt;&lt;/STRONG&gt;void Wait(CancellationToken cancellationToken)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Task: &lt;BR&gt;&lt;/STRONG&gt;void Wait(CancellationToken cancellationToken) &lt;BR&gt;void WaitAll(Task[] tasks, CancellationToken cancellationToken)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In each case, you supply a CancellationToken to the method, and if the CancellationToken is signaled via a call to the associated CancellationTokenSource.Cancel(), then the method will wake up and throw an OperationCanceledException. This frees you from the need to use the timeouts if you are happy to wait until the condition is true or a specific cancellation request occurs. Many of these methods also have overloads that accept both a CancellationToken and a timeout, so that both needs may be accommodated. &lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Long-running calls&lt;/H3&gt;
&lt;P&gt;There are also a variety of methods that may simply take a while to complete, particularly if large amounts of data or complex processing is taking place. For example, the following call is likely to take some time, even if individual calls to DoFunc(x) are relatively fast:&lt;/P&gt;
&lt;P&gt;Parallel.For(1, 1000000000, (x) =&amp;gt; DoFunc(x));&lt;/P&gt;
&lt;P&gt;To assist with this, the Parallel APIs have overloads that accept a ParallelOptions class instance that holds a CancellationToken. The machinery inside Parallel.For(...)observes the supplied CancellationToken and will exit early if it sees that the token has be signaled (for more information on exiting loops early, see &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/05/27/9645023.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/27/9645023.aspx"&gt;http://blogs.msdn.com/pfxteam/archive/2009/05/27/9645023.aspx&lt;/A&gt;). For example, &lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;ParallelOptions options = new ParallelOptions &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {CancellationToken = cts.Token}; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;Parallel.For(1, 100, options, (x) =&amp;gt; DoSlowFunc(x)); &lt;BR&gt;// from another thread, call cts.Cancel() to request cancellation.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;As you can see, the approach for canceling blocking calls and long-running calls is identical. In both cases you supply a CancellationToken to a specific method call and use the associated CancellationTokenSource to signal a cancellation request. &lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Digression: Internal cancellation&lt;/H3&gt;
&lt;P&gt;In certain situations in Parallel Extensions and in other systems, it is necessary to wake up a blocked method for reasons that aren't due to explicit cancellation by a user. For example, if one thread is blocked on blockingCollection.Take() due to the collection being empty and another thread subsequently calls blockingCollection.CompleteAdding(), then the first call should wake up and throw an InvalidOperationException to represent an incorrect usage. A great way to implement this is to use an internal CancellationTokenSource that can wake things up due to internal concerns, and to link it to a second, external CancellationTokenSource that has been supplied by the user. For example, the following captures the essential details of how CompleteAdding() and Take(CancellationToken) are implemented:&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;class BlockingCollection&amp;lt;T&amp;gt; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource internalCTS = new CancellationTokenSource();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; public void FinishAdding() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internalCTS.Cancel(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;public T Take(CancellationToken externalToken) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; using(CancellationTokenSource linkedTokenSource = &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CancellationTokenSource.CreateLinkedTokenSource( &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; internalCTS.Token, externalToken)){ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return InternalTake(linkedTokenSource.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch (OperationCanceledException oce) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(internalCTS.Token.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new InvalidOperationException("..msg.."); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if(externalToken.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(externalToken); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else throw; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;} &lt;BR&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;In this fragment, a linked CancellationTokenSource is created and its token passed to the InternalTake() method. This simplifies the implementation for InternalTake() but still allows it to be woken up due to either the external token being signaled or an incorrect concurrent call to CompleteAdding(). If the InternalTake() method throws an OperationCanceledException, we can test the individual tokens to determine what the cause was and take appropriate action. Note that oce.CancellationToken will be equal to linkedTokenSource.Token as this is the token that was actually being observed, but we can look at the original tokens to determine the cause for the linked token being signaled. There is a minor risk of confusion if both sources are signaled simultaneously, but this confusion is benign as it is reasonable to behave as though either source was responsible, and a particular implementation may choose to prioritize one mechanism over the other. &lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Cooperative cancellation with user-code&lt;/H3&gt;
&lt;P&gt;Both TPL and PLINQ provide infrastructure that calls back to user code. If the user code is long running or blocking, then it is very useful for the user code to be able to respond to cancellation in a cooperative fashion. TPL and PLINQ achieve this by tracking a supplied CancellationToken, and if they see some user code throw an OperationCanceledException that mentions this specific token, then it is treated as &lt;I&gt;cooperative acknowledgement of cancellation&lt;/I&gt;. This means that both TPL and PLINQ understand that the user code did not suffer some catastrophic exceptional conditional, but rather that it is simply responding to cancellation. As a result, TPL and PLINQ constructs will simply exit with an OperationCanceledException of their own, rather than aggregating exceptions from all the participating worker threads and throwing an AggregateException.&lt;/P&gt;
&lt;P&gt;PLINQ follows this basic plan; for example, the following query will throw a single OperationCanceledException if the CancellationTokenSource becomes signaled. It doesn't matter whether PLINQ or the user delegate sees the cancellation request first, as the user-delegate exception will be correctly understood by the PLINQ execution engine.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;var resultArray = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;data.AsParallel() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithCancellation(cts.Token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Select((x) =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (cts.Token.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(cts.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // ... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ToArray();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In both PLINQ and TPL, it is interesting to note that the external cancellation token is not supplied back to the user-delegate via a parameter as may be expected. This would have bloated the number of method overloads considerably and, as shown above, the external token can be conveniently accessed via closures or equivalent techniques.&lt;/P&gt;
&lt;P&gt;If the user code throws an OperationCanceledException but one or more "normal" exceptions occur on other threads, then all of the exceptions will be collated into an AggregateException, including the OperationCanceledException. Hence, if only cancellation occurred then a single OperationCanceledException is thrown, but an actual failure will always result in an AggregateException. &lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;PLINQ Queries&lt;/H3&gt;
&lt;P&gt;PLINQ offers deep support for cancellation and endeavors to ensure that cancellation will be enacted swiftly for any query. For queries that involve only simple and fast user delegates, simply supply a CancellationToken via the WithCancellation() method and PLINQ takes care of the rest. &lt;A&gt;&lt;FONT color=#000000&gt;If your query involves long-running or blocking user code, then you should use the cooperative cancellation pattern described in the preceding section&lt;/FONT&gt;&lt;/A&gt;. For reasons that are discussed in the next section, PLINQ may not check for cancellation every time it calls a user-delegate, and so long running delegates should check cancellation frequently (&lt;A&gt;&lt;FONT color=#000000&gt;as a working rule of thumb, PLINQ will check for cancellation approximately once per one hundred calls to a user delegate&lt;/FONT&gt;&lt;/A&gt;). For example, if a delegate call runs for 50ms but does not perform any cancellation checks of its own, then PLINQ may not detect the cancellation request itself for up to 5 seconds, and this could significantly affect a user’s experience. For this reason, we recommend that long-running delegates called from PLINQ queries should check for cancellation as frequently as possible. A good lower bound is to check cancellation once per few thousand IL instructions executed, and an upper bound is to check no less frequently than once per 10ms, but once per 1ms is preferred to ensure snappy response.&lt;/P&gt;
&lt;P&gt;The following example demonstrates a user delegate that may run for a while, and so checks cancellation itself every few thousand IL instructions. This provides for timely cancellation support with a negligible cost to performance.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face="Courier New"&gt;// Assume an external CancellationToken 'token' has been supplied. &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;int[] data = ...; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;var query = &lt;BR&gt;&amp;nbsp;&amp;nbsp; data.AsParallel() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithCancellation(token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Select((x) =&amp;gt; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int result = 0; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for ( int i = 0; i &amp;lt; x; i++ ) { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (int j = 0; j &amp;lt; 1000 * x; j++) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; result += SimpleFunc(i,j); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; token.ThrowIfCancellationRequested(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;}) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face="Courier New"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ToArray();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;[Update: the call to token.ThrowIfCancellationRequested shown above is not available in Beta1 (but will appear in subsequent releases).&amp;nbsp; This behavior can be acheived via a manual test-and-throw as shown in earlier examples, or via the extension-method approach described in the comments.&amp;nbsp; -Mike]&lt;/P&gt;
&lt;H3&gt;Summary&lt;/H3&gt;
&lt;P&gt;The Parallel Extension types use the new cancellation system to provide consistent and rich cancellation features. All of the long-running and blocking methods in Parallel Extensions provide overloads that take a CancellationToken, and any callbacks made to user-code can participate in the process. Application code can also make use of the same ideas and facilities to ensure that cancellation can be a fully supported feature in any situation.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9791840" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CDS/default.aspx">CDS</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Cancellation/default.aspx">Cancellation</category></item><item><title>.NET 4 Cancellation Framework</title><link>http://blogs.msdn.com/pfxteam/archive/2009/05/22/9635790.aspx</link><pubDate>Sat, 23 May 2009 06:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9635790</guid><dc:creator>mikelid</dc:creator><slash:comments>24</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9635790.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9635790</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9635790</wfw:comment><description>&lt;P&gt;A very interesting addition to .NET 4 is a set of new types that specifically assist with building cancellation-aware applications and libraries. The new types enable rich scenarios for convenient and safe cancellation, and help simplify situations that used to be be difficult and error-prone and non-composable.&lt;/P&gt;
&lt;P&gt;The details of the new types are described below, but lets begin with some of the motivating principles that the new types were designed to support: &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;When any unit of work is commenced, it should have a consistent means to support early termination in response to a cancellation request. &lt;/LI&gt;
&lt;LI&gt;If some unit of work controls various other moving pieces, it should be able to conveniently chain cancellation requests to them. &lt;/LI&gt;
&lt;LI&gt;Blocking calls should be able to support cancellation. &lt;/LI&gt;
&lt;LI&gt;Calls to complex operations, such as MoveNext() on a PLINQ enumerator, should have simple yet comprehensive cancellation support. &lt;/LI&gt;
&lt;LI&gt;When infrastructure makes calls back to potentially long-running user code, it should be possible for the user code to observe and respond to cancellation requests in a cooperative fashion. &lt;/LI&gt;
&lt;LI&gt;Cancellation should be an obvious part of an API with clean and consistent semantics. &lt;/LI&gt;
&lt;LI&gt;Cancellation should not be forceful but instead cooperative.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;In many prevailing systems, cancellation has been a secondary feature that rarely gets treated in sufficient detail to enable all of the above principles in a comprehensive fashion. The new types introduced to .NET 4 raise cancellation to be a primary concept for .NET APIs and one that can be cleanly and easily incorporated into any system.&lt;/P&gt;
&lt;H3&gt;Previous approaches&lt;/H3&gt;
&lt;P&gt;Cancellation is a feature that finds its way into many APIs and applications either by design or by necessity. An interesting classification of common approaches is Herb Sutter's article &lt;A href="http://www.ddj.com/hpc-high-performance-computing/207100682" mce_href="http://www.ddj.com/hpc-high-performance-computing/207100682"&gt;"Interrupt Politely"&lt;/A&gt;, which outlines four distinct techniques. Those four techniques can be distilled down to the two major techniques: The first is to use asynchronous, forced cancellation such as thread-abort, process-kill, or AppDomain-unload. Any asynchronous technique has the common trait that the target of cancellation is caught completely unaware and cannot easily ensure data safety. For many reasons, but particularly due to the risk of partial updates to shared data, the use of asynchronous techniques is strongly discouraged.&lt;/P&gt;
&lt;P&gt;The second general technique is cooperative whereby a request for cancellation is communicated to the target in some manner and the target of cancellation observes and enacts the request itself. This is inherently safer, but it does require that all targets of cancellation are fully participating in the process. The most commonly implemented style for this approach involves every potential target object tracking some state that represents whether cancellation has been requested although as we shall see this has some inherent problems and can be improved.&lt;/P&gt;
&lt;P&gt;.NET libraries in general follow the cooperative approach and various examples can be found; for example, the BackgroundWorker class in Windows Forms has a member called CancellationPending which is set to true by calling the method &lt;BR&gt;BackgroundWorker.CancelAsync(). Similarly, the classes based on System.Net.WebRequest provide an Abort() method to cancel the current operation and prevent further operations from commencing. A BackgroundWorker has a clear notion of the work that should be canceled, but a WebRequest may have either an active GetResponse() or GetRequestStream() call, and so the target of the cancellation request is not as clear. More generally, if a single object can be used to run distinct operations or if it can run many operations simultaneously, then it becomes very awkward to track cancellation requests on the object itself. And if the object allows the cancellation request to be reset either before or after enactment of a cancellation request, then there are inherent race conditions that can lead to subtle problems.&lt;/P&gt;
&lt;P&gt;So although cooperative cancellation is far superior to asynchronous cancellation, the common approach has the following issues:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Data is often imbued with a notion of cancellation, and this is a problematic abstraction. A better model is that specific occurrences of an &lt;I&gt;operation&lt;/I&gt; may be cancelable, but data is just data. &lt;/LI&gt;
&lt;LI&gt;Cancellation achieved by direct calls to Cancel() and Abort() methods on specific targets is not groupable or chainable. &lt;/LI&gt;
&lt;LI&gt;It is often necessary to perform some work in addition to setting a Boolean flag when enacting cancellation, but this support is not standardized or ubiquitous. &lt;/LI&gt;
&lt;LI&gt;If an operation on an object makes a callback to user code, it is often awkward to forward the cancellation request made on the parent object to the user code. &lt;/LI&gt;
&lt;LI&gt;If a class tracks cancellation state but allows multiple concurrent operations, or if it allows operations to commence after an earlier operation was canceled , then race-conditions become an inherent issue that frequently leads to subtle bugs. &lt;/LI&gt;
&lt;LI&gt;When cancellation is requested, identified and enacted, the resulting behaviors are not consistent. Some methods return as if nothing happened, some throw OperationCanceledException, some throw custom exceptions, and some return a custom error code. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;It is to address these issues that .NET 4 introduces a new approach to cooperative cancellation. And as we will examine in a future blog post, this approach is perfectly suited to the needs of Parallel Extensions and has been adopted across all our types.&lt;/P&gt;
&lt;H3&gt;New cancellation types&lt;/H3&gt;
&lt;P&gt;The new types provide a cooperative cancellation framework that is rich and general purpose. Some specific design principles of the new approach are:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Only specific framework types should represent a request for cancellation. &lt;/LI&gt;
&lt;LI&gt;Long-running or blocking methods should accept an explicit parameter that will inform the method of a cancellation request.&amp;nbsp; This is in contrast to mechanisms whereby operations automatically attach themselves to an &lt;EM&gt;ambient&lt;/EM&gt; cancellation-request object, such as one that has been stashed in thread-local-storage. Mechanisms that involve automatic discovery and attachment generally become awkward when the exact specification of the rules are fleshed out. &lt;/LI&gt;
&lt;LI&gt;The response made when cancellation is enacted should be to throw a consistent exception type. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Two new types form the basis of the framework: A &lt;EM&gt;CancellationToken&lt;/EM&gt; is a struct that represents a ‘potential request for cancellation’. This struct is passed into method calls as a parameter and the method can poll on it or register a callback to be fired when cancellation is requested. A &lt;EM&gt;CancellationTokenSource &lt;/EM&gt;is a class that provides the mechanism for initiating a cancellation request and it has a Token property for obtaining an associated token. It would have been natural to combine these two classes into one, but this design allows the two key operations (initiating a cancellation request vs. observing and responding to cancellation) to be cleanly separated. In particular, methods that take only a CancellationToken can observe a cancellation request but cannot initiate one.&lt;/P&gt;
&lt;P&gt;When a call is made to CancellationTokenSource.Cancel(), the IsCancellationRequested property of any associated CancellationToken will become true and methods can poll on this to observe the cancellation request. If polling is not possible or not convenient, a callback can be attached via CancellationToken.Register(). A CancellationToken can be copied and passed around and all the copies will simply point back to the original CancellationTokenSource which holds all the actual state regarding cancellation requests, callback lists, etc.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_4.png" mce_href="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_4.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: block; FLOAT: none; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN-LEFT: auto; BORDER-LEFT-WIDTH: 0px; MARGIN-RIGHT: auto" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_thumb_1.png" width=480 height=153 mce_src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_thumb_1.png"&gt;&lt;/A&gt;When methods see that CancellationToken.IsCancellationRequested == true, they should respond to this by throwing an OperationCanceledException(cancellationToken). Throwing this exception communicates that the method finished without fully completing its stated purpose and states which CancellationToken it observed. Note that the existing OperationCanceledException class has been augmented with constructors and a property for CancellationToken.&lt;/P&gt;
&lt;P&gt;We can now look at some specific examples: the first example shows how to create a CancellationTokenSource, pass its associated CancellationToken to a method, and how to poll on that token and correctly throw an OperationCanceledException. Note that cancellation doesn't need to be checked after every single statement, but it might be checked once per few thousand instructions or so. A general guideline is that cancellation should be checked as frequently as possible subject only to avoiding significant performance impact. Because polling on ct.IsCancellationRequested is very cheap (a single volatile read and a handful of IL instructions), cancellation can be tested frequently without a significant performance impact.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;EventHandler externalEvent; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;void Example1() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; externalEvent += &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (sender, obj) =&amp;gt; { cts.Cancel(); }; //wire up an external requester &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; try &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int val = LongRunningFunc(cts.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; catch (OperationCanceledException) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //cleanup after cancellation if required... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;private static int LongRunningFunc(CancellationToken token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; int total = 0; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; for(int i=0; i&amp;lt;1000; i++){ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for (int j = 0; j &amp;lt; 1000; j++) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; total++; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(token.IsCancellationRequested){ // observe cancellation &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(token); // acknowledge cancellation &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; return total; &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The second example demonstrates using the callback facility on CancellationToken for when polling is not an option.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;void BlockingOperation(CancellationToken token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; ManualResetEvent mre = new ManualResetEvent(false); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; //register a callback that will set the MRE &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; CancellationTokenRegistration registration = &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; token.Register(() =&amp;gt; mre.Set()); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; using (registration) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mre.WaitOne(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (token.IsCancellationRequested) //did cancellation wake us? &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } //dispose the registration, which performs the deregisteration. &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;A common pattern in these situations is to use the callback to force whatever condition the blocking call is waiting on, and then immediately check to see if cancellation was the reason the blocking call was woken. Although there is a race condition here that normal waking may occur just before a cancellation request is made, this race is benign as it is always safe to respond to the cancellation request regardless of why the wait finished.&lt;/P&gt;
&lt;P&gt;The third example shows how to listen for cancellation via a regular WaitHandle. Under the covers, CancellationToken.WaitHandle is a lazily-allocated ManualResetEvent that becomes set when cancellation is requested.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;void Wait(WaitHandle wh, CancellationToken token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; WaitHandle.WaitAny(new [] {wh, token.WaitHandle}); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; if (token.IsCancellationRequested) //did cancellation wake us? &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;And finally, the fourth example shows running multiple asynchronous operations which share a common CancellationToken.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;void Example4() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; StartAsyncFunc1(cts.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; StartAsyncFunc2(cts.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; StartAsyncFunc3(cts.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; //... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; cts.Cancel(); // all listeners see the same cancellation request. &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In particular it is interesting to note that each of the asynchronous functions might pass on the token to other methods and that everyone who is observing the token (or copies of the token) will see the cancellation request when cts.Cancel() is called. &lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Details&lt;/H3&gt;
&lt;P&gt;A few details are important for an understanding of the new approach.&lt;/P&gt;
&lt;P&gt;A CancellationTokenSource may transition from non-canceled only once and cannot be reset. This prevents various race-conditions that arise deep inside method calls if reset were permitted. At an application level, however, reset functionality is often required and this is achieved by creating a new CancellationTokenSource to replace a used one.&lt;/P&gt;
&lt;P&gt;A CancellationToken is a lightweight struct that includes only a single reference back to a CancellationTokenSource. As such, it is the same ‘weight’ as a normal object reference, but because it is a separate type, it can have its own API than provides only read operations.&lt;/P&gt;
&lt;P&gt;When a callback is registered to a CancellationToken, the current thread's ExecutionContext is captured so that the callback will be run with the the exact same security context . The capturing of the current thread's synchronization context is optional can be requested via an overload of ct.Register() if required. Callbacks are normally stored and then run when cancellation is requested, but if a callback is registered after cancellation has been requested, the callback will run immediately on the current thread, or via Send() on the current SynchronizationContext if applicable.&lt;/P&gt;
&lt;P&gt;When a callback is registered to a CancellationToken, the returned object is a CancellationTokenRegistration. This is a light struct type that is IDiposable, and disposing this registration object causes the callback to be deregistered. A guarantee is made that after the Dispose() method has returned, the registered callback is neither running nor will subsequently commence. A consequence of this is that CancellationTokenRegistration.Dispose()must block if the callback is currently executing. Hence, all registered callbacks should be fast and not block for any significant duration. &lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;Advanced patterns&lt;/H3&gt;
&lt;P&gt;To finish this introduction to the new cancellation framework we can look briefly at two more advanced patterns of usage.&lt;/P&gt;
&lt;P&gt;One situation that arises is that some methods wish to observe two separate tokens. The best approach here is to create a linked CancellationTokenSource that will be signaled if either of the source tokens has become signaled.&lt;/P&gt;
&lt;P align=center&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_6.png" mce_href="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_6.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=image border=0 alt=image src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_thumb_2.png" width=480 height=126 mce_src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/NET4.0CancellationFramework_A897/image_thumb_2.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The method CancellationTokenSource.CreateLinkedTokenSource() is specifically designed to assist with this and registers the callbacks as required. For example:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;void LinkingExample(CancellationToken ct1, CancellationToken ct2) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource linkedCTS = &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource.CreateLinkedTokenSource(ct1, ct2); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; try &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SlowFunc(linkedCTS.Token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; catch(OperationCanceledException oce) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (ct1.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // ... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if (ct2.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // ... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; linkedCTS.Dispose(); // clean up the linking. required. &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;By using cancellation linking, cancellation-aware methods need only take one CancellationToken parameter. Be aware however that because linking attaches callbacks onto the source tokens, it is very important to clean up properly, otherwise linkedCTS and the callback delegates cannot be garbage collected until the linked sources are also available for collection. This is achieve by explicitly disposing linkedCTS, or via the using() pattern.&lt;/P&gt;
&lt;P&gt;Another scenario that arises is to allow library code and user code to cooperate when responding to cancellation. Consider a library method that accepts a CancellationToken, and then calls back to user code. If the user code responds to a cancellation request, it wants to communicate this cleanly to the library code. This is achieved by the user code throwing an OperationCanceledException that mentions the same CancellationToken that the library code was given. Typically the user code will know about the same CancellationToken by getting it through some side channel, e.g. via closure-capture, rather than the library method explicitly passing it on. For example:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;private void RunQuery() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;int[] data = {1,2,3}; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; CancellationTokenSource cts = new CancellationTokenSource(); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; var query = data.AsParallel() &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithCancellation(cts.Token) // token given to library code &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Select( (x) =&amp;gt; SlowFunc(x, cts.Token) ); // token passed to user code &lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2 face=Consolas&gt;private int SlowFunc(int x, CancellationToken token) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;{ &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; int result &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; while(...) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (token.IsCancellationRequested) &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new OperationCanceledException(token); &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ... &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;&amp;nbsp;&amp;nbsp; return result; &lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2 face=Consolas&gt;}&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Notice that the library function (in this case a PLINQ query) and the user code are both observing the same token and that the user-code throws an OperationCanceledException that mentions this common token. This allows the library code to see that the user code has performed cooperative cancellation and has not simply thrown some arbitrary exception. The library may respond to this by behaving exactly as though it had seen the cancellation request itself, rather than thinking the user code failed unexpectedly. It also has the advantage that if the user code throws an OperationCanceledException for some unexpected reason (and mentions a different token or no token at all), it will not be mistakenly interpreted as cooperative cancellation. Because the token is tracked in the OperationCanceledException itself, there is no confusion about the reason for the exception being thrown.&lt;/P&gt;
&lt;H3&gt;Conclusion&lt;/H3&gt;
&lt;P&gt;The new cancellation types introduced to .NET 4 provide a new framework for building systems that have rich and consistent cancellation behaviors. This will specifically assist with GUIs, applications, and libraries that manage long running or blocking operations. Over time we expect to see more libraries migrate to this approach and reduce the variation and issues inherent in the current crop of cancellation solutions. Applications and 3rd-party libraries can use these new types to interoperate cleanly with Parallel Extensions and for their own purposes.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9635790" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CDS/default.aspx">CDS</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Beta/default.aspx">Beta</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Cancellation/default.aspx">Cancellation</category></item><item><title>Samples for Parallel Programming with the .NET Framework 4</title><link>http://blogs.msdn.com/pfxteam/archive/2009/05/20/9633116.aspx</link><pubDate>Thu, 21 May 2009 03:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9633116</guid><dc:creator>toub</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9633116.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9633116</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9633116</wfw:comment><description>&lt;P&gt;Along with the release of the &lt;A href="http://blogs.msdn.com/pfxteam/archive/2009/05/20/9632991.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2009/05/20/9632991.aspx"&gt;.NET Framework 4 Beta 1&lt;/A&gt;, we've just published a slew of samples that demonstrate using Parallel Extensions in a variety of ways.&amp;nbsp; You can download these from Code Gallery at &lt;A href="http://code.msdn.microsoft.com/ParExtSamples"&gt;http://code.msdn.microsoft.com/ParExtSamples&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;These samples include raytracers, a sudoku game, an image colorization algorithm, solvers for the n-queens problem, fractal image generators, and more.&amp;nbsp; The samples include code written to use Parallel Extensions from C#, Visual Basic, F#, and C++/CLI.&amp;nbsp; They include examples of using the Task Parallel Library, PLINQ, new coordination data structures, and even databinding a WPF UI to a collection that has data stored into it&amp;nbsp;from a&amp;nbsp;background thread.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;On top of all of this, the samples include a project called "Parallel Extensions Extras", which features a healthy portion of extension methods for .NET 4 types, new data structures to augment what's being shipped in .NET 4, custom schedulers for TPL, and lots of other goodness.&amp;nbsp; Definitely worth a perusal.&lt;/P&gt;
&lt;P&gt;Enjoy!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9633116" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CDS/default.aspx">CDS</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Visual+Studio+2010/default.aspx">Visual Studio 2010</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/.NET+4.0/default.aspx">.NET 4.0</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Beta/default.aspx">Beta</category></item><item><title>Concurrent, Multi-core Programming on Windows and .NET</title><link>http://blogs.msdn.com/pfxteam/archive/2008/10/27/9019731.aspx</link><pubDate>Tue, 28 Oct 2008 08:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9019731</guid><dc:creator>toub</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/9019731.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=9019731</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=9019731</wfw:comment><description>&lt;P&gt;Thanks to everyone who attended our PDC pre-conference session yesterday on parallelism and concurrency!&amp;nbsp; We had a wonderful turnout at the event, and David, Joe, and I all had a terrific time. &lt;A class="" href="http://blogs.msdn.com/pfxteam/attachment/9019731.ashx" mce_href="http://blogs.msdn.com/pfxteam/attachment/9019731.ashx"&gt;Attached&lt;/A&gt; to this post are the slides we presented.&lt;/P&gt;
&lt;P&gt;(It turns out that the PDC site does allow you to &lt;A href="https://sessions.microsoftpdc.com/public/evals.aspx" mce_href="https://sessions.microsoftpdc.com/public/evals.aspx"&gt;submit an evaluation&lt;/A&gt; for a precon.&amp;nbsp; If you attended, we'd love your &lt;A href="https://sessions.microsoftpdc.com/public/evals.aspx" mce_href="https://sessions.microsoftpdc.com/public/evals.aspx"&gt;feedback&lt;/A&gt;.)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9019731" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pfxteam/attachment/9019731.ashx" length="1451170" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/ThreadPool/default.aspx">ThreadPool</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallelism+Blockers/default.aspx">Parallelism Blockers</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Talks/default.aspx">Talks</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/C_2B002B00_/default.aspx">C++</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Tools/default.aspx">Tools</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Release/default.aspx">Release</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CTP/default.aspx">CTP</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CDS/default.aspx">CDS</category></item><item><title>Feedback requested: Enumerating Concurrent Collections</title><link>http://blogs.msdn.com/pfxteam/archive/2008/08/12/8852005.aspx</link><pubDate>Tue, 12 Aug 2008 18:51:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8852005</guid><dc:creator>toub</dc:creator><slash:comments>24</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8852005.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8852005</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8852005</wfw:comment><description>&lt;p&gt;The &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3"&gt;June 2008 CTP of Parallel Extensions&lt;/a&gt; contained a first look at some of the work we're doing to augment the .NET Framework with a set of additional coordination data structures that aid in the development of highly concurrent applications.&amp;#160; This included two thread-safe collections, ConcurrentQueue&amp;lt;T&amp;gt; and ConcurrentStack&amp;lt;T&amp;gt;, and it's probably not giving away too much to say that we're working diligently on additional collections that aid in key scenarios for parallel programming.&amp;#160; For the most part, these collections are similar to the exsiting non-thread-safe counterparts in the .NET Framework, except with APIs designed with concurrency patterns in mind, and of course implementations that tolerate multithreaded access.&amp;#160; Some of these designs come naturally and, from an implementation standpoint, are easily enabled.&amp;#160; However, there are times when we have to make significant trade-offs in functionality or performance in order to achieve certain designs, and for those situations, it's very important that we have a good understanding of the key scenarios and use cases in which the collections will be used.&lt;/p&gt;  &lt;p&gt;One important design point we keep in mind for all of the collections we're working on is how to deal with concurrent modifications while a collection is being enumerated.&amp;#160; With the standard collections in the .NET Framework today, modifications to a collection invalidate any outstanding enumerators.&amp;#160; For example, consider the following code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var q = new Queue&amp;lt;int&amp;gt;(new[] { 1, 2, 3, 4, 5 });      &lt;br /&gt;foreach (var item in q)       &lt;br /&gt;{       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (item &amp;lt;= 5) q.Enqueue(item * 6);       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This will compile fine, but upon execution, the call to q.Enqueue inside of the foreach loop will throw an InvalidOperationException: &amp;quot;Collection was modified after the enumerator was instantiated.&amp;quot;&amp;#160; In contrast, if you change the Queue&amp;lt;int&amp;gt; to a ConcurrentQueue&amp;lt;int&amp;gt;, e.g.:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;var q = new ConcurrentQueue&amp;lt;int&amp;gt;(new[] { 1, 2, 3, 4, 5 });      &lt;br /&gt;foreach (var item in q)       &lt;br /&gt;{       &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (item &amp;lt;= 5) q.Enqueue(item * 6);       &lt;br /&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;no exception will be thrown, and upon examination of the queue after the loop, you'll find it to contain 10 elements.&amp;#160; This is an explicit design decision we've made to break the mold from the existing collections, the idea behind such a change in direction being that there are key scenarios where one thread needs to be enumerating while other threads are reading and writing to the collection (of course, as shown in this example, it could be the same thread reading and writing as the one enumerating).&lt;/p&gt;  &lt;p&gt;This does raise some questions, of course, especially around the guarantees that can be provided for such an enumeration.&amp;#160; If data is added to the list while another thread is enumerating, must that enumerating thread see the new data?&amp;#160; If data is removed while another thread is enumerating, must that enumerating thread not see the new data?&amp;#160; Is it acceptable for data to be observed twice in the same enumeration or not at all due to the organization of the collection being changed concurrently?&amp;#160; And so forth.&amp;#160; For some collections, like ConcurrentStack&amp;lt;T&amp;gt; and ConcurrentQueue&amp;lt;T&amp;gt;, we're able to provide moment-in-time snapshot semantics, but for other collection types, doing so isn't necessarily possible without incurring serious performance penalties.&lt;/p&gt;  &lt;p&gt;Given this, we're very curious to hear your feedback on a few things:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Given the standard array of collections that exist in .NET, if you had thread-safe versions of them, are there scenarios where you would benefit from being able to enumerate concurrently with other threads modifying the same collection?&amp;#160; We already know about some, but we'd love to hear about more. &lt;/li&gt;    &lt;li&gt;Assuming you do have scenarios for #1, what are the minimum guarantees you'd need about the data returned in the enumerator for it to be useful?&amp;#160; For example, you could say for a thread-safe dictionary that if there are no concurrent modifications (adds/updates/removals), you'll get back in the enumeration exactly what's in the dictionary, and if there are concurrent accesses, you'll never get back something that wasn't in the dictionary, you may not see concurrent adds or updates, and you may still see items that are concurrently removed. &lt;/li&gt;    &lt;li&gt;If we did support enumeration on collections that were thread-safe in the face of concurrent modifications, would you ever want the ability to revert to the &amp;quot;throw on modifications&amp;quot; behavior? &lt;/li&gt;    &lt;li&gt;Finally, what are the most important collections that you'd like to see thread-safe and scalable counterparts for?&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Thanks in advance for any input you may have!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8852005" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Feedback+Requested/default.aspx">Feedback Requested</category></item><item><title>Waiting for Tasks</title><link>http://blogs.msdn.com/pfxteam/archive/2008/08/05/8835612.aspx</link><pubDate>Wed, 06 Aug 2008 04:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8835612</guid><dc:creator>toub</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8835612.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8835612</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8835612</wfw:comment><description>&lt;P&gt;Parallel Extensions makes it easy to wait for Tasks to complete.&amp;nbsp; Task exposes a Wait method, which can be used trivially:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Task t = Task.Create(...); &lt;BR&gt;... &lt;BR&gt;t.Wait();&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Task also exposes several static methods for waiting on an array of tasks, either for all of them to complete or for any of them to complete:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Task t1 = Task.Create(...); &lt;BR&gt;Task t2 = Task.Create(...); &lt;BR&gt;Task t3 = Task.Create(...); &lt;BR&gt;... &lt;BR&gt;Task.WaitAll(t1, t2, t3); // or Task.WaitAny(t1, t2, t3)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Moreover, Tasks have implicit parent/child relationships, and a parent Task will wait for any of its child tasks to complete before it completes:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Task p = Task.Create(delegate &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Task c1 = Task.Create(...); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Task c2 = Task.Create(...); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Task c3 = Task.Create(...); &lt;BR&gt;}); &lt;BR&gt;... &lt;BR&gt;p.Wait(); // will not wake up until c1, c2, and c3 have finished&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Sometimes, however, you want to wait for a list of tasks to complete, but you don't necessarily want to have to hold onto references to all of the relevant Task objets.&amp;nbsp; Imagine a scenario where I'm creating tasks for each of an unknown number of data elements to be processed:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;IEnumerable&amp;lt;Data&amp;gt; data = ...; &lt;BR&gt;List&amp;lt;Task&amp;gt; tasks = new List&amp;lt;Task&amp;gt;(); &lt;BR&gt;foreach(var item in data) tasks.Add(Task.Create(delegate { Process(item); }); &lt;BR&gt;Task.WaitAll(tasks.ToArray());&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The code is straightforward, but it also requires that I hold onto references to all of the Tasks I've created so that I can wait for all of them.&amp;nbsp; It's interesting to note, however, that a task that has already completed doesn't really need to be waited on.&amp;nbsp; As an example, if I create 10 tasks and 9 of them complete, waiting on the remaining 1 task is sufficient to know that all 10 completed.&amp;nbsp; This means that I only really need to wait on a count of tasks, where each new task increases the count, and where each task completing decreases the count: when the count reaches 0, all tasks have completed.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Sound familiar? This is the domain of a CountdownEvent, which we can use to codify this approach:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;IEnumerable&amp;lt;Data&amp;gt; data = ...; &lt;BR&gt;using(CountdownEvent tasksRemaining = new CountdownEvent(1)) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach(var item in data) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; tasksRemaining.Increment(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Task.Create(delegate &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Process(item); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; taskRemaining.Decrement(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; tasksRemaining.Decrement(); // to counteract the initial 1 &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; tasksRemaining.Wait(); &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The CountdownEvent is initialized to a count of 1 to ensure that the event doesn't become signaled before I'm done creating all of the tasks; I remove that 1 count when all tasks have been created.&amp;nbsp; Before creating each Task, I up the count by 1, and when each task finishes, I decrease the count by 1.&amp;nbsp; Then I just wait on the CountdownEvent, which will be signaled when all of the tasks have completed.&lt;/P&gt;
&lt;P&gt;Of course, this requires that I incorporate such logic directly into my code, but there's really no need for that.&amp;nbsp; I can extract out this logic into a separate class:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public class TaskWaiter &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public CountdownEvent _ce = new CountdownEvent(1); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private bool _doneAdding = false; &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Add(Task t) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (t == null) throw new ArgumentNullException("t");&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ce.Increment(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; t.ContinueWith(ct =&amp;gt; _ce.Decrement()); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Wait() &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!_doneAdding) { _doneAdding = true; _ce.Decrement(); }&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ce.Wait(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Rewriting the previous example is now almost identical, just substituting TaskWaiter for the List&amp;lt;Task&amp;gt;:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;IEnumerable&amp;lt;Data&amp;gt; data = ...; &lt;BR&gt;TaskWaiter tasks = new TaskWaiter(); &lt;BR&gt;foreach(var item in data) tasks.Add(Task.Create(delegate { Process(item); }); &lt;BR&gt;tasks.Wait();&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Unlike the previous implementation that uses a List&amp;lt;Task&amp;gt;, this implementation now doesn't need to store references to any of the tasks.&amp;nbsp; For just a few tasks, it's probably not warranted.&amp;nbsp; But if lots of tasks are being create and/or any of the tasks will be long-running such that holding onto tasks could cause them to be promoted to higher GC generations, this could have a noticeable impact on the application's performance.&lt;/P&gt;
&lt;P&gt;One neat thing to notice about the implementation of TaskWaiter: it uses ContinueWith.&amp;nbsp; I previously wrote about &lt;A href="http://blogs.msdn.com/pfxteam/archive/2008/07/23/8768673.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2008/07/23/8768673.aspx"&gt;useful abstractions enabled with ContinueWith&lt;/A&gt;, and this is another such abstraction.&amp;nbsp; ContinueWith is used in order to get a bit of extra code to execute when a Task complete, such that the CountdownEvent is properly decremented.&amp;nbsp; This allows me to move that Decrement call out of the Task's body itself (as I had with the original CountdownEvent-based implementation shown earlier), which means this technique can be used with any arbitrary Task you're handed, rather than one you have to create yourself.&lt;/P&gt;
&lt;P&gt;There are some downsides to the TaskWaiter approach, however.&amp;nbsp; The biggest that jumps to mind with the current implementation is that we lose the ability to propagate any exceptions that may have occurred from tasks tracked by TaskWaiter.&amp;nbsp; We can fix that by storing references to tasks that complete with unhandled exceptions, and then do a true wait only on those tasks:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;public class TaskWaiter &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public CountdownEvent _ce = new CountdownEvent(1); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private bool _doneAdding = false; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private ConcurrentQueue&amp;lt;Task&amp;gt; _faulted = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; new ConcurrentQueue&amp;lt;Task&amp;gt;(); &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Add(Task t) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (t == null) throw new ArgumentNullException("t");&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ce.Increment(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; t.ContinueWith(ct =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (ct.Exception != null) _faulted.Enqueue(ct); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ce.Decrement(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void Wait() &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!_doneAdding) { _doneAdding = true; _ce.Decrement(); }&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _ce.Wait();&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!_faulted.IsEmpty) Task.WaitAll(_faulted.ToArray()); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Notice the few changes.&amp;nbsp; A ConcurrentQueue&amp;lt;Task&amp;gt; was added to track any tasks that completed due to exception; this collection needs to be thread-safe, as multiple tasks could fail on different threads and attempt to access the queue from different threads, hence the ConcurrentQueue&amp;lt;Task&amp;gt;.&amp;nbsp; The delegate passed to ContinueWith has been augmented to check to see if the completing Task completed due to an exception, and if it did, the Task is added to the queue.&amp;nbsp; Then in Wait, after waiting on the CountdownEvent, I use Task.WaitAll to wait on all of the tasks that completed due to exceptions.&amp;nbsp; By this point, they've of course already completed, so I'm using Task.WaitAll simply to aggregate and throw all of the exceptions.&lt;/P&gt;
&lt;P&gt;There's a subtlety about how I made these changes that's important to keep in mind.&amp;nbsp; Specifically, it's crucial that the faulting task be added to the ConcurrentQueue&amp;lt;T&amp;gt; before the CountdownEvent is decremented; if those lines were reversed in the ContinueWith delegate, the CountdownEvent could become set before the Task was tracked in the queue, in which case the exceptions from that Task may be missed in the call to TaskWaiter.Wait, since the Task may not yet have made it into the queue by the time Task.WaitAll is called.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;There are, of course, other optimizations that could be made to an implementation like this one, but we'll save those for another day.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8835612" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category></item><item><title>Useful Abstractions Enabled with ContinueWith</title><link>http://blogs.msdn.com/pfxteam/archive/2008/07/23/8768673.aspx</link><pubDate>Thu, 24 Jul 2008 07:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8768673</guid><dc:creator>toub</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8768673.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8768673</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8768673</wfw:comment><description>&lt;P&gt;In the June 2008 CTP of &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&amp;amp;displaylang=en"&gt;Parallel Extensions to the .NET Framework&lt;/A&gt;, we introduced the ContinueWith method on both Task and Future&amp;lt;T&amp;gt;.&amp;nbsp; ContinueWith is, in effect, a callback, very much like events in .NET.&amp;nbsp; With events, a causal action results in the event being raised, which by default triggers all of the delegates registered with the event to be invoked.&amp;nbsp; ContinueWith supports this, but rather than just registering the callback, it also provides back a Task or Future&amp;lt;T&amp;gt; that represents the callback; that returned Task or Future&amp;lt;T&amp;gt;'s lifecycle is tied specifically to the callback and won't be marked as IsCompleted until that callback completes.&amp;nbsp; While at its core this could be considered a relatively simple idea and is useful for general dataflow in applications, it also enables some important patterns and can serve as the building block for a whole host of larger abstractions.&lt;/P&gt;
&lt;P&gt;For example, the June 2008 CTP doesn't provide support for mulit-item continuations (is this something you think we should provide in a future release?): you can create a continuation Task or Future&amp;lt;T&amp;gt; for when one Task or Future&amp;lt;T&amp;gt; finishes, but out-of-the-box you can't create one for when all of multiple Task or Future&amp;lt;T&amp;gt;'s complete.&amp;nbsp; Nevertheless, you can use the basic ContinueWith support to implement this additional support.&amp;nbsp; Here's an example of a ContinueWith method you could implement, where you provide it with multiple Task instances, and the resulting Task will only be scheduled and executed when all of the provided tasks complete (I've ommitted parameter validation and the like to simplify the code):&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;static Task ContinueWhenAll( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Action&amp;lt;Task[]&amp;gt; continuation, params Task[] tasks) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var starter = Future&amp;lt;bool&amp;gt;.Create(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var task = starter.ContinueWith(o =&amp;gt; continuation(tasks)); &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CountdownEvent ce = new CountdownEvent(tasks.Length); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Action&amp;lt;Task&amp;gt; whenComplete = delegate { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (ce.Decrement()) starter.Value = true; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var t in tasks) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; t.ContinueWith(whenComplete, TaskContinuationKind.OnAny, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TaskCreationOptions.None, true); &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return task; &lt;BR&gt;} &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This ContinueWhenAll method tasks two parameters: an Action&amp;lt;Task[]&amp;gt; to execute when all of the provided tasks have completed (supplied with those tasks), and the params array of the Tasks to monitor for completion.&amp;nbsp; It then uses a workaround to create a Task that can be started at an arbitrary time in the future (in the June 2008 CTP, we don't directly support this capability, hence the workaround, but we're planning to in a future release as that capability is useful for a bunch of scenarios, including this one).&amp;nbsp; A delegate is created that will count down from the number of provided tasks every time it's invoked, and when the count reaches 0, it will start the task.&amp;nbsp; ContinueWith is then used to register that whenComplete action as a continuation for all of the parameter tasks.&amp;nbsp; And voila, we now have a ContinueWhenAll method, which can be used like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Task t1 = ..., t2 = ...; &lt;BR&gt;Task t3 = ContinueWhenAll( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; delegate { Console.WriteLine("t1 and t2 finished"); }, t1, t2);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Similarly, a method could be implemented for creating a task continuation for when any of a set of tasks completes (rather than when they all complete):&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;static Task ContinueWhenAny( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Action&amp;lt;Task&amp;gt; continuation, params Task[] tasks) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WriteOnce&amp;lt;Task&amp;gt; theCompletedTask = new WriteOnce&amp;lt;Task&amp;gt;(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var starter = Future&amp;lt;bool&amp;gt;.Create(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var task = starter.ContinueWith(o =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; continuation(theCompletedTask.Value)); &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Action&amp;lt;Task&amp;gt; whenComplete = t =&amp;gt; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (theCompletedTask.TrySetValue(t)) starter.Value = true; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (var t in tasks) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; t.ContinueWith(whenComplete, TaskContinuationKind.OnAny, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TaskCreationOptions.None, true); &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return task; &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This implementation is very similar to ContinueWhenAll.&amp;nbsp; However, the action that's registered as the continuation for each task uses a WriteOnce&amp;lt;T&amp;gt; to store the first Task to complete and to schedule the continuation task when it does.&amp;nbsp; ContinueWhenAny can be used like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Task t1 = ..., t2 = ...; &lt;BR&gt;Task t3 = ContinueWhenAny( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; delegate { Console.WriteLine("t1 or t2 finished"); }, t1, t2);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;There are other neat patterns enabled with ContinueWith.&amp;nbsp; One pattern that's starting to become popular with frameworks like the CCR or AsyncEnumerator is to take advantage of C#'s iterator support to make writing code that uses asynchronous operations a bit more like sequential code.&amp;nbsp; While not the primary focus of the Task Parallel Library, ContinueWith can be used to implement such patterns in at least a limited capacity.&amp;nbsp; Consider the following method:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;static void RunAsync(IEnumerable&amp;lt;Task&amp;gt; iterator) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var enumerator = iterator.GetEnumerator(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Action a = null; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; a = delegate &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (enumerator.MoveNext()) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; enumerator.Current.ContinueWith(delegate { a(); }); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; else enumerator.Dispose(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; a(); &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This method accepts an IEnumerable&amp;lt;Task&amp;gt;.&amp;nbsp; It retrieves an enumerator from the enumerable and uses that enumerator in a delegate.&amp;nbsp; The delegate moves the enumerator to its next element, and if there is a next element, retrieves it and uses ContinueWith to schedule the delegate (recursively, in a sense) for execution when that current Task completes.&amp;nbsp; When the enumerator reaches the end, it's disposed.&amp;nbsp; With that delegate created, RunAsync simply executes the delegate to get the execution started.&lt;/P&gt;
&lt;P&gt;Now imagine I wanted a method that would asynchronously read a file, processing it as it's read in.&amp;nbsp; I can implement such a method as follows:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;static IEnumerable&amp;lt;Task&amp;gt; ReadFile(string path) &lt;BR&gt;{ &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; using (FileStream fs = new FileStream( &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, true)) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var enc = new UTF8Encoding(); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; byte[] data = new byte[0x1000]; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (true) &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var pendingRead = CreateFutureFromApm&amp;lt;int&amp;gt;(ac =&amp;gt; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; fs.BeginRead(data, 0, data.Length, ac, null), fs.EndRead); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield return pendingRead; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int bytesRead = pendingRead.Value; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (bytesRead &amp;lt;= 0) break; &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(enc.GetString(data, 0, bytesRead)); &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;ReadFile opens a file stream and continually reads from it asynchronously.&amp;nbsp; The code wraps usage of the FileStream's BeginRead/EndRead methods with a Future&amp;lt;int&amp;gt; (using the example method from &lt;A href="http://blogs.msdn.com/8272833.aspx" mce_href="http://blogs.msdn.com/8272833.aspx"&gt;http://blogs.msdn.com/8272833.aspx&lt;/A&gt;); that Future&amp;lt;int&amp;gt; is yielded from the ReadFile method (which returns an enumerator).&amp;nbsp; We'll execute ReadFile by passing it to RunAsync.&amp;nbsp; When the Future&amp;lt;int&amp;gt; completes, its continuation will be executed, which will cause the RunAsync iterator to MoveNext, thus ending up back in the ReadFile method just after the yield location.&amp;nbsp; The ContinueWhenAll method can be used to allow more complicated asynchronous methods to be written, by wrapping multiple asynchronous invocations and yielding a continuation for when they all complete.&lt;/P&gt;
&lt;P&gt;There are a myriad of such interesting patterns that ContinueWith enables.&amp;nbsp; We'd love to hear about any useful ones you come up with.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8768673" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category></item><item><title>More Channel 9 Parallel Extensions Goodness</title><link>http://blogs.msdn.com/pfxteam/archive/2008/06/06/8579465.aspx</link><pubDate>Sat, 07 Jun 2008 07:09:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8579465</guid><dc:creator>toub</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8579465.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8579465</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8579465</wfw:comment><description>&lt;p&gt;Charles from &lt;a href="http://channel9.msdn.com/"&gt;Channel 9&lt;/a&gt; came over to building 112 last week for an in-depth look at what's new in the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=348F73FD-593D-4B3C-B055-694C50D2B0F3"&gt;June 2008 CTP of Parallel Extensions&lt;/a&gt;.&amp;#160; We spoke on the subject for an hour and a half or so, which you can see in a two-part series that was posted to Channel 9 yesterday (by the way, Channel 9 team, the new site looks great!):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a title="http://channel9.msdn.com/shows/Going+Deep/Inside-Parallel-Extensions-for-NET-2008-CTP-Part-1/" href="http://channel9.msdn.com/shows/Going+Deep/Inside-Parallel-Extensions-for-NET-2008-CTP-Part-1/"&gt;http://channel9.msdn.com/shows/Going+Deep/Inside-Parallel-Extensions-for-NET-2008-CTP-Part-1/&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a title="http://channel9.msdn.com/shows/Going+Deep/Inside-Parallel-Extensions-for-NET-2008-CTP-Part-2/" href="http://channel9.msdn.com/shows/Going+Deep/Inside-Parallel-Extensions-for-NET-2008-CTP-Part-2/"&gt;http://channel9.msdn.com/shows/Going+Deep/Inside-Parallel-Extensions-for-NET-2008-CTP-Part-2/&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;What better way to spend some of this weekend than to enjoy discussions of Parallel Extensions. :) As always, we're very interested in your feedback, on the CTP itself but also on what we discussed in the videos and on what we should discuss in future videos.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8579465" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Media/default.aspx">Media</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/CTP/default.aspx">CTP</category></item><item><title>Ray Tracer samples in the June 2008 CTP</title><link>http://blogs.msdn.com/pfxteam/archive/2008/06/04/8573863.aspx</link><pubDate>Thu, 05 Jun 2008 06:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8573863</guid><dc:creator>mikelid</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8573863.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8573863</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8573863</wfw:comment><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;The June 2008 Community Technology Preview (CTP) of Parallel Extensions to the .NET Framework was released on Monday, and we’re really pleased at the level of excitement in the community that we’re seeing in response.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;As part of the CTP, we included a &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;variety of demos and samples to help provide a tour of the functionality.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If you haven't already, please read the blog entries: &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567802.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567802.aspx"&gt;&lt;FONT face=Calibri size=3&gt;Released! Parallel Extensions to the .NET Framework June 2008 CTP&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Calibri size=3&gt;, &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567816.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567816.aspx"&gt;&lt;FONT face=Calibri size=3&gt;Known Issues in the June 2008 CTP of Parallel Extensions&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=Calibri size=3&gt;, and &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567093.aspx" mce_href="http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567093.aspx"&gt;&lt;FONT face=Calibri size=3&gt;What's New in the June 2008 CTP of Parallel Extensions&lt;/FONT&gt;&lt;/A&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;In this post, I’m going to explore the four separate ray tracer implementations in the samples that demonstrate how to utilize Parallel Extensions to achieve concurrent rendering (note that the actual ray tracing engine itself is not an optimized implementation, as it is intended more for discussion than performance).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;There were two forms of the base sequential ray tracer, both developed by Luke Hoban, one written in C# using standard loops and other imperative programming constructs, and another implemented in C# via some huge LINQ queries that define the entire execution (read about this implementation at &lt;/FONT&gt;&lt;A href="http://blogs.msdn.com/lukeh/archive/2007/04/03/a-ray-tracer-in-c-3-0.aspx" mce_href="http://blogs.msdn.com/lukeh/archive/2007/04/03/a-ray-tracer-in-c-3-0.aspx"&gt;&lt;FONT face=Calibri size=3&gt;http://blogs.msdn.com/lukeh/archive/2007/04/03/a-ray-tracer-in-c-3-0.aspx&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The samples in the CTP extend these examples in the following ways:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpFirst style="MARGIN: 0in 0in 0pt 0.5in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1"&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-fareast-font-family: Calibri; mso-bidi-theme-font: minor-latin; mso-fareast-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT face=Calibri size=3&gt;1.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The original C# ray tracer is converted to use Parallel Extensions (both the Task Parallel Library and some of the new Coordination Data Structures) to achieve concurrency.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This enhanced version was then ported to Visual Basic and F#, demonstrating that Parallel Extensions is usable from any .NET language.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;See …&lt;I style="mso-bidi-font-style: normal"&gt;\Samples\RayTracer\...&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoListParagraphCxSpLast style="MARGIN: 0in 0in 3pt 0.5in; TEXT-INDENT: -0.25in; mso-list: l0 level1 lfo1"&gt;&lt;SPAN style="mso-bidi-font-family: Calibri; mso-fareast-font-family: Calibri; mso-bidi-theme-font: minor-latin; mso-fareast-theme-font: minor-latin"&gt;&lt;SPAN style="mso-list: Ignore"&gt;&lt;FONT face=Calibri size=3&gt;2.&lt;/FONT&gt;&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The LINQ-style ray tracer is converted to use PLINQ&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;to achieve concurrency.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;See&lt;I style="mso-bidi-font-style: normal"&gt; …\Samples\LINQRayTracer&lt;/I&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;These ray tracer samples involve a fair number of concurrency primitives provided by Parallel Extensions:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.Parallel&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.Task&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.TaskManager&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.TaskManagerPolicy&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.LazyInit&amp;lt;T&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.Collections.IConcurrentCollection&amp;lt;T&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Threading.Collections.ConcurrentQueue&amp;lt;T&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt; TEXT-INDENT: 0.5in"&gt;&lt;FONT face="Courier New"&gt;System.Linq.ParallelQuery&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;These samples also involve some standard .NET concurrency primitives and patterns:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;System.Threading.Interlocked&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code-inline style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;System.Windows.Forms.Control.BeginInvoke&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;System.Threading.Monitor&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; (via the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;lock {…}&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;construct)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;SPAN style="mso-tab-count: 1"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Let’s start by exploring the C# ray tracer.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Load up &lt;I style="mso-bidi-font-style: normal"&gt;Samples\RayTracer\C#\RayTracer.sln&lt;/I&gt;, compile and run.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If you receive errors regarding System.Threading, please ensure that you have the .NET Framework 3.5 and the Parallel Extensions June 2008 CTP installed.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Once the app is running, press the Start button and the ray tracer animation will run in single-threaded mode:&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt" mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;IMG title="Ray tracer in sequential mode" style="WIDTH: 238px; HEIGHT: 244px" height=244 alt="Ray tracer in sequential mode" src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/RayTracerSamplesintheJune2008CTP2_BEBD/clip_image002_2.jpg" width=238 align=middle mce_src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/RayTracerSamplesintheJune2008CTP2_BEBD/clip_image002_2.jpg"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt; TEXT-ALIGN: center" align=center&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /&gt;&lt;v:shapetype id=_x0000_t75 coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"&gt;&lt;v:stroke joinstyle="miter"&gt;&lt;/v:stroke&gt;&lt;v:formulas&gt;&lt;v:f eqn="if lineDrawn pixelLineWidth 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 1 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum 0 0 @1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @2 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @3 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @0 0 1"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @6 1 2"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelWidth"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @8 21600 0"&gt;&lt;/v:f&gt;&lt;v:f eqn="prod @7 21600 pixelHeight"&gt;&lt;/v:f&gt;&lt;v:f eqn="sum @10 21600 0"&gt;&lt;/v:f&gt;&lt;/v:formulas&gt;&lt;v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"&gt;&lt;/v:path&gt;&lt;o:lock v:ext="edit" aspectratio="t"&gt;&lt;/o:lock&gt;&lt;/v:shapetype&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Note that the frames-per-second is displayed in the form’s title bar, and that there are controls to Start/Stop the animation and to turn on parallel rendering.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The “Parallel” checkbox enables switching back and forth between sequential and parallel rendering, while the "Show Threads" option (only available when using parallel rendering) performs color-adjustment on the rendered pixels to indicate which thread each pixel was rendered on.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Let’s turn on Parallel computation with "Show Threads" and observe the effect, shown here on a quad-core PC:&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;o:p&gt;&lt;IMG title="Ray tracer in parallel mode" style="WIDTH: 238px; HEIGHT: 244px" height=244 alt="Ray tracer in parallel mode" src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/RayTracerSamplesintheJune2008CTP2_BEBD/clip_image004_2.jpg" width=238 align=middle mce_src="http://blogs.msdn.com/blogfiles/pfxteam/WindowsLiveWriter/RayTracerSamplesintheJune2008CTP2_BEBD/clip_image004_2.jpg"&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt; TEXT-ALIGN: center" align=center&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;In this screenshot, we can clearly see four separate colorings, which represent the four underlying threads that are calculating pixel values for the rendered image.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Notice also that the allocation of pixels to threads is row-based and that the partitioning of work is not uniform based on row-counts.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is due to &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Parallel.For()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;dynamically assigning work to the worker threads to ensure that the computational load remains.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The application code itself specifies that the work should be split up row-by-row as this is a good balance between fine-grained work decomposition and the overheads inherent in spooling out small work items.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;That is, if the work was decomposed to per-pixel work-items, the extra overheads would negatively impact the performance.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;As it is, parallelizing the row-by-row decomposition provides a 3x improvement when the colorization is turned off.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is a good result, as there is a non-trivial amount of work to be done that cannot be parallelized – note that even though the timing is around the image calculation only, drawing the image to the screen and refreshing the form eats into the cycles available and affects the speed-up factor.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If drawing the image is omitted, the speed up is between 3.5x and 4x as expected and hoped for. The moral here is that drawing more images to the screen increases the overheads of the parallel renderer and that we should always keep Amdahl's Law (&lt;/FONT&gt;&lt;A href="http://en.wikipedia.org/wiki/Amdahl's_law" mce_href="http://en.wikipedia.org/wiki/Amdahl's_law"&gt;&lt;FONT face=Calibri size=3&gt;http://en.wikipedia.org/wiki/Amdahl's_law&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;)&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;in mind when assessing parallel improvements.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The key rendering loops are RenderSequential(), RenderParallel(), and RenderParallelShowingThreads(), all of which appear in Raytracer.cs.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Comparing the first two, we see that the only difference is a simple rewriting of the outer loops: &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;for(int y=0; y &amp;lt; screenHeight; y++){ /* funcBody */&amp;nbsp;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;to &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: #2b91af; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;Parallel&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;.For(0, screenHeight, y =&amp;gt; /* funcBody */&amp;nbsp;)&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;A critical part of any parallel application is that the concurrent work (such as the funcBody in the parallel version) is thread-safe. This means that &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TraceRay()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; and other work called in the parallel loop must not alter any shared-state unless appropriate thread-synchronization is used or if the updates are known to be safe.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;You will note that the funcBody's do alter a shared data-structure, &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;rgb[]&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;, but that each element in this array will only be written to by a single execution of the funcBody and so no conflict will arise.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The developer must always be vigilant that all concurrent work can occur without conflicts.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;If in doubt, simplify the concurrent work, use locks around risky code, or analyze the code and test to ensure corrrectness.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;The application also makes use of a single &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;System.Threading.Task&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; to manage the whole process of running the animation, and to set the options regarding parallelism via a &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TaskManager&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TaskManager&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; that is provided to this task become the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TaskManager.Current&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; for every task that is created inside, and so the configuration options also apply to the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Parallel.For()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; that runs within the task (since &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Parallel.For()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; is built using &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Task&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;, and &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Task&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; instances by default use &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TaskManager.Current&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Another useful feature of wrapping the animation loop in a task is to provide a simple means of tracking whether the animation is running, and to facilitate cancelling the animation.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Diving in to &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;btnStartStop_Click()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt; in MainForm.cs, we see &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;_renderTask = &lt;SPAN style="COLOR: #2b91af"&gt;Task&lt;/SPAN&gt;.Create(RenderLoop, &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;chkParallel.Checked ? _parallelTm.Value : _sequentialTm.Value);&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;o:p&gt;&lt;FONT face="Courier New"&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;which creates the task to wrap the &lt;/FONT&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;RenderLoop()&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; and supplies a &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TaskManager&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; to control the options for parallel execution.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The first &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;TaskManager&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;, &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;_parallelTm&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;, will schedule one thread on every core of the machine, whereas &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;_sequentialTm&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; only uses one thread on one core in order to simulate a simple sequential implementation.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Actually, each of these variables is actually a &lt;/FONT&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: #2b91af; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;LazyInit&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%; FONT-FAMILY: 'Courier New'; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;TaskManager&lt;/SPAN&gt;&amp;gt; &lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;which ensure creation of the main type only if the variable is used.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This is a minor usage of &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;LazyInit&amp;lt;T&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt; but the construct can be very useful for object creations that are expensive and avoidable; in this example, if you never run a parallel render, you’ll never instantiate the parallel TaskManager.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Keep this handy construct in mind for objects that might go unused.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;The code for handling the "stop-animation" action includes the following:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;_renderTask.ContinueWith(&lt;SPAN style="COLOR: blue"&gt;delegate&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;BeginInvoke((&lt;SPAN style="COLOR: #2b91af"&gt;Action&lt;/SPAN&gt;)&lt;SPAN style="COLOR: blue"&gt;delegate&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;chkParallel.Enabled = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;chkShowThreads.Enabled = chkParallel.Checked;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;btnStartStop.Enabled = &lt;SPAN style="COLOR: blue"&gt;true&lt;/SPAN&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;btnStartStop.Text = &lt;SPAN style="COLOR: #a31515"&gt;"Start"&lt;/SPAN&gt;;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;_renderTask.Cancel();&lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;This sets a continuation-handler for the task that is wrapping the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;RenderLoop()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;, and this continuation cleans up the GUI and re-enables various controls.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Notice that we must use &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;MainForm.BeginInvoke()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; in order to run the clean-up code on the GUI thread, as tasks run on a background worker thread.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;After the cleanup continuation is registered, we call &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Task.Cancel()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Notice that the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;RenderLoop()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; is checking for &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;t.IsCanceled&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; in order to detect the cancellation and co-operatively bail out of its animation loop.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The standard overload for &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Task.ContinueWith()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;will run the continuation whenever the task finishes, whether due to successful termination, failure or cancellation, but there are additional overloads to control when the continuation fires and other task-related options.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=Codei style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;There is an interesting system used for managing the bitmaps used for rendering.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In particular, allocation of the image bitmaps is expensive, but we don’t want to have to wait for the GUI to display a bitmap before we start computation of the next.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;One way to solve this is a classic double-buffered solution with one bitmap for scene-drawing and another that is ready for &lt;I style="mso-bidi-font-style: normal"&gt;blitting&lt;/I&gt; to the screen (this was the approach taken in the sample included with the December 2007 CTP).&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;A more general solution is to keep rendering images at the maximum rate and add them to a queue for blitting.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;This solution has been implemented by using a set of bitmaps for drawing, and each is sent for blitting by calling &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;Form.BeginInvoke()&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt;with an appropriate delegate. &lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;In order to reuse bitmaps rather than creating and disposing them repeatedly, an &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;ObjectPool&amp;lt;T&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; (see ObjectPools.cs) has been built around a &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;ConcurrentQueue&amp;lt;T&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; that supports object reuse and creation of new objects if no reusable ones are available.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;ConcurrentQueue&amp;lt;T&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT face=Calibri size=3&gt; is particularly useful as it provides all the machinery required to make the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;ObjectPool&amp;lt;T&amp;gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt; thread-safe.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;The C# ray tracer has been ported to Visual Basic and F#, including all of the items discussed above except for image colorization.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;To build and run the F# version, download the F# languge support pack from &lt;/FONT&gt;&lt;A href="http://research.microsoft.com/fsharp/fsharp.aspx" mce_href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;&lt;FONT face=Calibri size=3&gt;http://research.microsoft.com/fsharp/fsharp.aspx&lt;/FONT&gt;&lt;/A&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;. (To compile the sample, if you’re running on x64, you’ll need to modify the project settings to point to System.Core.dll in the correct location, as it’s a different path than if running on x86.) In particular, notice that F# can directly make direct use of the Parallel Extensions and also gets an excellent performance boost on multi-core PCs:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;member this.RenderToArrayParallel(scene, rgb : int[]) = &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Parallel.For(0, screenHeight, fun y -&amp;gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;let stride = y * screenWidth&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;for x = 0 to screenWidth - 1 do &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;let color = TraceRay ({Start = scene.Camera.Pos; Dir = GetPoint x y scene.Camera }, scene, 0)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;let intColor = color.ToInt ()&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;rgb.[x + stride] &amp;lt;- intColor)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;Finally, a completely different ray tracer implementation is shown in Samples\LINQRayTracer.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;When you run this ray tracer, you will notice that it has a more complicated scene and does not perform animation, but as it renders you will see the concurrency in effect as the rows get drawn.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;The original query was written in the form:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: blue; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;from&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt; y &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, screenHeight)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="COLOR: blue; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;…&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: blue; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;select&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt; &lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; x &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, screenWidth)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;which is a natural 2-D construct to loop over each pixel in each row.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;In order to make this run concurrently on a per-row basis (as for the other ray tracers), we only have to ask for the outer query to be run in parallel mode:&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: blue; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;from&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt; y &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, screenHeight).&lt;B style="mso-bidi-font-weight: normal"&gt;&lt;I style="mso-bidi-font-style: normal"&gt;AsParallel()&lt;/I&gt;&lt;/B&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="COLOR: blue; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;…&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="COLOR: blue; mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;select&lt;/SPAN&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt; &lt;SPAN style="COLOR: blue"&gt;from&lt;/SPAN&gt; x &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Enumerable&lt;/SPAN&gt;.Range(0, screenWidth)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt;This sets the query to use PLINQ to partition the work of outer query over all the available cores.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;The other adjustment is to enumerate the query via &lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;pixelsQuery.ForAll(row =&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;foreach&lt;/SPAN&gt; (&lt;SPAN style="COLOR: blue"&gt;var&lt;/SPAN&gt; pixel &lt;SPAN style="COLOR: blue"&gt;in&lt;/SPAN&gt; row)&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;rgb[pixel.X + (pixel.Y * screenWidth)] = pixel.Color.ToInt32();&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt; processed = &lt;SPAN style="COLOR: #2b91af"&gt;Interlocked&lt;/SPAN&gt;.Increment(&lt;SPAN style="COLOR: blue"&gt;ref&lt;/SPAN&gt; rowsProcessed);&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if&lt;/SPAN&gt; (processed % rowsPerUpdate == 0 ||&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;processed &amp;gt;= screenHeight) updateImageHandler(rgb);&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=Code style="MARGIN: 0in 0in 0pt 9pt"&gt;&lt;SPAN style="mso-no-proof: yes; mso-bidi-language: AR-SA"&gt;&lt;FONT face="Courier New"&gt;});&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;FONT face=Calibri size=3&gt;which causes the query to run to completion in parallel.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;Notice that the per-row worker delegate includes thread-safe access to the &lt;/FONT&gt;&lt;SPAN class=Code-inlineChar&gt;&lt;SPAN style="FONT-SIZE: 10pt; LINE-HEIGHT: 115%"&gt;&lt;FONT face="Courier New"&gt;rowsProcessed&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;FONT size=3&gt;&lt;FONT face=Calibri&gt; counter to be safe in concurrent execution.&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 3pt"&gt;&lt;o:p&gt;&lt;FONT face=Calibri size=3&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8573863" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category></item><item><title>What's New in the June 2008 CTP of Parallel Extensions</title><link>http://blogs.msdn.com/pfxteam/archive/2008/06/02/8567093.aspx</link><pubDate>Mon, 02 Jun 2008 18:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8567093</guid><dc:creator>toub</dc:creator><slash:comments>33</slash:comments><comments>http://blogs.msdn.com/pfxteam/comments/8567093.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pfxteam/commentrss.aspx?PostID=8567093</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pfxteam/rsscomments.aspx?PostID=8567093</wfw:comment><description>&lt;P&gt;We've just released a new community technology preview (CTP) of Parallel Extensions to the .NET Framework!&amp;nbsp; You can download it from &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&lt;/A&gt;.&amp;nbsp; This release contains a plethora of bug fixes as well as some design changes to address some great feedback from you (note that there are some other changes you've requested and that we're planning to make in future releases, so stay tuned).&amp;nbsp; It also contains a wealth of new functionality, some under the covers, some exposed through new APIs.&lt;/P&gt;
&lt;H5&gt;Task Parallel Library&lt;/H5&gt;
&lt;P&gt;The December 2007 CTP included an implementation of the Task Parallel Library (TPL) built on top of a prototype scheduler. As we’ve moved forward with Parallel Extensions, we’ve replaced this prototype with a new scheduler that is built from the ground up to be more robust, efficient, and scalable. The scheduler uses cooperative scheduling and work-stealing to achieve fast, efficient scheduling and maximum CPU utilization. The June 2008 CTP of Parallel Extensions includes this new scheduler, with TPL running on top of it. &lt;BR&gt;While lots of work has been done with the internals of TPL, new functionality has also been exposed through its APIs. A new continuation model has been added to the System.Threading.Tasks.Task and System.Threading.Tasks.Future&amp;lt;T&amp;gt; classes through a new set of ContinueWith methods on both Task and Future&amp;lt;T&amp;gt;, enabling new tasks to be scheduled when previous tasks complete. This is especially powerful for Future&amp;lt;T&amp;gt;, where the continuations are provided with the completed Future&amp;lt;T&amp;gt; and thus with access to its &lt;A href="http://blogs.msdn.com/controlpanel/blogs/html/bbe7a0d4-8642-a688-1bae-5890ddb84a39.htm" mce_href="html/bbe7a0d4-8642-a688-1bae-5890ddb84a39.htm"&gt;Value&lt;/A&gt;, enabling dataflow-oriented solutions, e.g.:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;futureC = &lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; A()).&lt;BR&gt;                     ContinueWith(a =&amp;gt; B(a.Value)).&lt;BR&gt;                     ContinueWith(b =&amp;gt; C(b.Value));&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Continuations can be scheduled to run under a variety of circumstances, such as when a task completes due to an unhandled exception. &lt;/P&gt;
&lt;P&gt;Other new functionality includes a new set of WaitAny methods on Task that serve as counterparts to Task’s WaitAll methods (TaskCoordinator, which existed in the December 2007 CTP as the base class for Task and which exposed the WaitAll methods, has been removed). WaitAny enables a developer to wait for any one of a set of tasks to complete, which can be useful for a variety of scenarios, including speculative execution. Consider a problem where multiple heuristics can be used to solve the problem, but it’s not known a priori which algorithm will solve the problem the fastest. If it’s not feasible to parallelize each of the algorithms, the algorithms could all be run in parallel with one another, and the developer can use WaitAny to wait for the first algorithm to complete, e.g.: &lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;algorithms = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt;[] {
    &lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; Alg1()) ,
    &lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; Alg2()) ,
    &lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; Alg3()) ,
    &lt;SPAN style="COLOR: #2b91af"&gt;Future&lt;/SPAN&gt;.Create(() =&amp;gt; Alg4()) };
&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;result = algorithms[&lt;SPAN style="COLOR: #2b91af"&gt;Task&lt;/SPAN&gt;.WaitAny(algorithms)].Value;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Several new properties have emerged on the Task class. The Name property that appeared in the December 2007 CTP has been replaced by an Id property, and a Creator property has been added. Creator returns the Task that was current when the Task was created. Creator is similar but is not always identical to the Parent property. New in this CTP is an improved notion of task hierarchies and relationships between parent and child tasks. By default, a Task is parented to the Task that was current when it was created; in this case, both Parent and Creator will return the same Task instance. However, Tasks can be created detached from their creator (by specifying the TaskCreationOptions.Detached value), in which case Parent will return null. This is an important capability, because now by default parent tasks implicitly wait on their children before completing, enabling a more structured form of task parallelism and aiding in a developer’s ability to write a correct, task-based application.&lt;/P&gt;
&lt;P&gt;A variety of additional and minor API changes have also surfaced in this CTP. The TaskManagerPolicy class contains new values, representing concepts such as the minimum number of processors to use, the ideal number of processors to use, the ideal number of threads to use per processor, the stack size to use per thread, and the thread priority to assign to threads. At a higher-level, the Parallel.Do method has been renamed to Parallel.Invoke. Significant effort has also been invested in fixing bugs in functionality.&lt;/P&gt;
&lt;H5&gt;PLINQ&lt;/H5&gt;
&lt;P&gt;The most important changes in this CTP are implementation details for improving the reliability and debuggability of PLINQ. One such change: whereas PLINQ in the December 2007 CTP release was built on top of the .NET ThreadPool, PLINQ in this CTP is now built on top of the Task Parallel Library. Note, however, that this implementation is minimalistic. The plan is for future releases to take advantage of more of the functionality the Task Parallel Library has to offer. &lt;/P&gt;
&lt;P&gt;In addition to implementation changes, new APIs are present in this CTP. First and foremost, the APIs for specifying order-preservation have been revamped. In the previous CTP, order-preservation was enabled on a query using the ParallelQueryOptions enumeration, such as in this example written in Visual Basic: &lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;Public Shared Function &lt;/SPAN&gt;Scramble(&lt;SPAN style="COLOR: blue"&gt;ByVal &lt;/SPAN&gt;words &lt;SPAN style="COLOR: blue"&gt;As String&lt;/SPAN&gt;()) &lt;SPAN style="COLOR: blue"&gt;As String&lt;/SPAN&gt;()
    &lt;SPAN style="COLOR: blue"&gt;Return &lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;From &lt;/SPAN&gt;word &lt;SPAN style="COLOR: blue"&gt;In &lt;/SPAN&gt;words.AsParallel(ParallelQueryOptions.PreserveOrdering) _
               &lt;SPAN style="COLOR: blue"&gt;Select &lt;/SPAN&gt;ScrambleWord(word)).ToArray()
&lt;SPAN style="COLOR: blue"&gt;End Function&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;The ParallelQueryOptions enumeration has been removed from the API set, and has been replaced by a new AsOrdered extension method, which can be used as follows: &lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;Public Shared Function &lt;/SPAN&gt;Scramble(&lt;SPAN style="COLOR: blue"&gt;ByVal &lt;/SPAN&gt;words &lt;SPAN style="COLOR: blue"&gt;As String&lt;/SPAN&gt;()) &lt;SPAN style="COLOR: blue"&gt;As String&lt;/SPAN&gt;()
    &lt;SPAN style="COLOR: blue"&gt;Return &lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;From &lt;/SPAN&gt;word &lt;SPAN style="COLOR: blue"&gt;In &lt;/SPAN&gt;words.AsParallel().AsOrdered() _
               &lt;SPAN style="COLOR: blue"&gt;Select &lt;/SPAN&gt;ScrambleWord(word)).ToArray()
&lt;SPAN style="COLOR: blue"&gt;End Function&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;An AsUnordered extension method also exists to enable the introduction of “shuffle points” into a query. If a certain portion of a query must be processed with a specific ordering, AsOrdered or OrderBy can be used to ensure that ordering is preserved, while AsUnordered can be used to in effect turn off ordering for portions of the query where performance is more important than ordering.&lt;/P&gt;
&lt;P&gt;Other API level changes include the introduction of a new extension method, Zip: &lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;public static &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IParallelEnumerable&lt;/SPAN&gt;&amp;lt;TResult&amp;gt; &lt;BR&gt;    Zip&amp;lt;TFirst, TSecond, TResult&amp;gt;(
      &lt;SPAN style="COLOR: blue"&gt;this &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;IParallelEnumerable&lt;/SPAN&gt;&amp;lt;TFirst&amp;gt; first, &lt;SPAN style="COLOR: #2b91af"&gt;IEnumerable&lt;/SPAN&gt;&amp;lt;TSecond&amp;gt; second,
      &lt;SPAN style="COLOR: #2b91af"&gt;Func&lt;/SPAN&gt;&amp;lt;TFirst, TSecond, TResult&amp;gt; resultSelector);&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Zip “zips together” two enumerables, creating a pairing of an item from each enumeration that is then passed to a function. An enumerable containing the results of that function is returned. This CTP also includes a parallel implementation of the SequenceEquals extension method, which was omitted from the previous CTP. Additionally, the Cast and OfType operators have been updated to conform to a breaking change in LINQ-to-Object’s implementation of these operators that’s available in the .NET Framework 3.5 SP1 (more information about this change is available at &lt;A title=http://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx href="http://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx" mce_href="http://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx"&gt;http://blogs.msdn.com/ed_maurer/archive/2008/02/16/breaking-change-in-linq-queries-using-explicitly-typed-range-variables.aspx&lt;/A&gt;). &lt;/P&gt;
&lt;H5&gt;Coordination Data Structures&lt;/H5&gt;
&lt;P&gt;The June 2008 CTP introduces a set of coordination data structures that complement PLINQ and the Task Parallel Library. The System.Threading namespace of the .NET Framework 3.5 already contains a handful of synchronization primitives, such as events, monitors, and mutexes, which are low-level constructs useful in developing multithreaded applications. Many parallel applications, however, would benefit greatly from higher-level constructs such as thread-safe collections, more sophisticated locking primitives, data structures to facilitate work exchange, and types that control how variables are initialized. Parallel Extensions adds a plethora of such constructs to the System.Threading and System.Threading.Collections namespaces. The types included in this CTP are: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;System.Threading.CountdownEvent &lt;/LI&gt;
&lt;LI&gt;System.Threading.LazyInit&amp;lt;T&amp;gt; &lt;/LI&gt;
&lt;LI&gt;System.Threading.ManualResetEventSlim &lt;/LI&gt;
&lt;LI&gt;System.Threading.SemaphoreSlim &lt;/LI&gt;
&lt;LI&gt;System.Threading.SpinLock &lt;/LI&gt;
&lt;LI&gt;System.Threading.SpinWait &lt;/LI&gt;
&lt;LI&gt;System.Threading.WriteOnce&amp;lt;T&amp;gt; &lt;/LI&gt;
&lt;LI&gt;System.Threading.Collections.BlockingCollection&amp;lt;T&amp;gt; &lt;/LI&gt;
&lt;LI&gt;System.Threading.Collections.ConcurrentQueue&amp;lt;T&amp;gt; &lt;/LI&gt;
&lt;LI&gt;System.Threading.Collections.ConcurrentStack&amp;lt;T&amp;gt; &lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8567093" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pfxteam/archive/tags/PLINQ/default.aspx">PLINQ</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Task+Parallel+Library/default.aspx">Task Parallel Library</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Code+Samples/default.aspx">Code Samples</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Parallel+Extensions/default.aspx">Parallel Extensions</category><category domain="http://blogs.msdn.com/pfxteam/archive/tags/Coordination+Data+Structures/default.aspx">Coordination Data Structures</category></item></channel></rss>