{"id":2603,"date":"2008-06-04T23:33:00","date_gmt":"2008-06-04T23:33:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/pfxteam\/2008\/06\/04\/ray-tracer-samples-in-the-june-2008-ctp\/"},"modified":"2008-06-04T23:33:00","modified_gmt":"2008-06-04T23:33:00","slug":"ray-tracer-samples-in-the-june-2008-ctp","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/ray-tracer-samples-in-the-june-2008-ctp\/","title":{"rendered":"Ray Tracer samples in the June 2008 CTP"},"content":{"rendered":"<p><P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">The June 2008 Community Technology Preview (CTP) of Parallel Extensions to the .NET Framework was released on Monday, and we\u2019re really pleased at the level of excitement in the community that we\u2019re seeing in response.<SPAN>&nbsp; <\/SPAN>As part of the CTP, we included a <SPAN>&nbsp;<\/SPAN>variety of demos and samples to help provide a tour of the functionality.<SPAN>&nbsp; <\/SPAN>If you haven&#8217;t already, please read the blog entries: <\/FONT><A href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2008\/06\/02\/8567802.aspx\"><FONT face=\"Calibri\" size=\"3\">Released! Parallel Extensions to the .NET Framework June 2008 CTP<\/FONT><\/A><FONT face=\"Calibri\" size=\"3\">, <\/FONT><A href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2008\/06\/02\/8567816.aspx\"><FONT face=\"Calibri\" size=\"3\">Known Issues in the June 2008 CTP of Parallel Extensions<\/FONT><\/A><FONT face=\"Calibri\" size=\"3\">, and <\/FONT><A href=\"https:\/\/blogs.msdn.com\/pfxteam\/archive\/2008\/06\/02\/8567093.aspx\"><FONT face=\"Calibri\" size=\"3\">What&#8217;s New in the June 2008 CTP of Parallel Extensions<\/FONT><\/A><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">In this post, I\u2019m 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).<SPAN>&nbsp; <\/SPAN>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 <\/FONT><A href=\"https:\/\/blogs.msdn.com\/lukeh\/archive\/2007\/04\/03\/a-ray-tracer-in-c-3-0.aspx\"><FONT face=\"Calibri\" size=\"3\">https:\/\/blogs.msdn.com\/lukeh\/archive\/2007\/04\/03\/a-ray-tracer-in-c-3-0.aspx<\/FONT><\/A><FONT size=\"3\"><FONT face=\"Calibri\">)<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">The samples in the CTP extend these examples in the following ways:<\/FONT><\/FONT><\/P>\n<P class=\"MsoListParagraphCxSpFirst\"><SPAN><SPAN><FONT face=\"Calibri\" size=\"3\">1.<\/FONT><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\">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.<SPAN>&nbsp; <\/SPAN>This enhanced version was then ported to Visual Basic and F#, demonstrating that Parallel Extensions is usable from any .NET language.<SPAN>&nbsp; <\/SPAN>See \u2026<I>\\Samples\\RayTracer\\&#8230;<\/I><\/FONT><\/FONT><\/P>\n<P class=\"MsoListParagraphCxSpLast\"><SPAN><SPAN><FONT face=\"Calibri\" size=\"3\">2.<\/FONT><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\">The LINQ-style ray tracer is converted to use PLINQ<SPAN>&nbsp; <\/SPAN>to achieve concurrency.<SPAN>&nbsp; <\/SPAN>See<I> \u2026\\Samples\\LINQRayTracer<\/I><\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">These ray tracer samples involve a fair number of concurrency primitives provided by Parallel Extensions:<\/FONT><\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.Parallel<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.Task<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.TaskManager<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.TaskManagerPolicy<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.LazyInit&lt;T&gt;<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.Collections.IConcurrentCollection&lt;T&gt;<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Threading.Collections.ConcurrentQueue&lt;T&gt;<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\">System.Linq.ParallelQuery<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">These samples also involve some standard .NET concurrency primitives and patterns:<\/FONT><\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>System.Threading.Interlocked<\/FONT><\/P>\n<P class=\"Code-inline\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>System.Windows.Forms.Control.BeginInvoke<\/FONT><\/P>\n<P class=\"MsoNormal\"><SPAN><FONT face=\"Calibri\" size=\"3\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">System.Threading.Monitor<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> (via the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">lock {\u2026}<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"><SPAN>&nbsp; <\/SPAN>construct)<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN><\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">Let\u2019s start by exploring the C# ray tracer.<SPAN>&nbsp; <\/SPAN>Load up <I>Samples\\RayTracer\\C#\\RayTracer.sln<\/I>, compile and run.<SPAN>&nbsp; <\/SPAN>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.<SPAN>&nbsp; <\/SPAN>Once the app is running, press the Start button and the ray tracer animation will run in single-threaded mode:<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\">&nbsp;<\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\"><IMG title=\"Ray tracer in sequential mode\" height=\"244\" alt=\"Ray tracer in sequential mode\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/21\/2019\/02\/clip_image002_2.jpg\" width=\"238\" align=\"middle\"><\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\" align=\"center\"><SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"><SPAN>&nbsp;<\/SPAN><\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">Note that the frames-per-second is displayed in the form\u2019s title bar, and that there are controls to Start\/Stop the animation and to turn on parallel rendering.<SPAN>&nbsp; <\/SPAN>The \u201cParallel\u201d checkbox enables switching back and forth between sequential and parallel rendering, while the &#8220;Show Threads&#8221; option (only available when using parallel rendering) performs color-adjustment on the rendered pixels to indicate which thread each pixel was rendered on.<SPAN>&nbsp; <\/SPAN>Let\u2019s turn on Parallel computation with &#8220;Show Threads&#8221; and observe the effect, shown here on a quad-core PC:<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\"><\/FONT>&nbsp;<\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\"><IMG title=\"Ray tracer in parallel mode\" height=\"244\" alt=\"Ray tracer in parallel mode\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/21\/2019\/02\/clip_image004_2.jpg\" width=\"238\" align=\"middle\"><\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\" align=\"center\"><SPAN><\/SPAN><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\"><\/FONT>&nbsp;<\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">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.<SPAN>&nbsp; <\/SPAN>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.<SPAN>&nbsp; <\/SPAN>This is due to <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Parallel.For()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">dynamically assigning work to the worker threads to ensure that the computational load remains.<SPAN>&nbsp; <\/SPAN>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.<SPAN>&nbsp; <\/SPAN>That is, if the work was decomposed to per-pixel work-items, the extra overheads would negatively impact the performance.<SPAN>&nbsp; <\/SPAN>As it is, parallelizing the row-by-row decomposition provides a 3x improvement when the colorization is turned off.<SPAN>&nbsp; <\/SPAN>This is a good result, as there is a non-trivial amount of work to be done that cannot be parallelized \u2013 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.<SPAN>&nbsp; <\/SPAN>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&#8217;s Law (<\/FONT><A href=\"http:\/\/en.wikipedia.org\/wiki\/Amdahl's_law\"><FONT face=\"Calibri\" size=\"3\">http:\/\/en.wikipedia.org\/wiki\/Amdahl&#8217;s_law<\/FONT><\/A><FONT size=\"3\"><FONT face=\"Calibri\">)<SPAN>&nbsp; <\/SPAN>in mind when assessing parallel improvements.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">The key rendering loops are RenderSequential(), RenderParallel(), and RenderParallelShowingThreads(), all of which appear in Raytracer.cs.<SPAN>&nbsp; <\/SPAN>Comparing the first two, we see that the only difference is a simple rewriting of the outer loops: <\/FONT><\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\">for(int y=0; y &lt; screenHeight; y++){ \/* funcBody *\/&nbsp;}<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">to <\/FONT><\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>Parallel<\/SPAN><SPAN>.For(0, screenHeight, y =&gt; \/* funcBody *\/&nbsp;)<\/SPAN><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">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 <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TraceRay()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> 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.<SPAN>&nbsp; <\/SPAN>You will note that the funcBody&#8217;s do alter a shared data-structure, <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">rgb[]<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\">, 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.<SPAN>&nbsp; <\/SPAN>The developer must always be vigilant that all concurrent work can occur without conflicts.<SPAN>&nbsp; <\/SPAN>If in doubt, simplify the concurrent work, use locks around risky code, or analyze the code and test to ensure corrrectness.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">The application also makes use of a single <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">System.Threading.Task<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> to manage the whole process of running the animation, and to set the options regarding parallelism via a <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TaskManager<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">.<SPAN>&nbsp; <\/SPAN>The <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TaskManager<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> that is provided to this task become the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TaskManager.Current<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> for every task that is created inside, and so the configuration options also apply to the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Parallel.For()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> that runs within the task (since <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Parallel.For()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> is built using <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Task<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">, and <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Task<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> instances by default use <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TaskManager.Current<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">).<SPAN>&nbsp; <\/SPAN>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.<SPAN>&nbsp; <\/SPAN>Diving in to <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">btnStartStop_Click()<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"> in MainForm.cs, we see <\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">_renderTask = <SPAN>Task<\/SPAN>.Create(RenderLoop, <\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>chkParallel.Checked ? _parallelTm.Value : _sequentialTm.Value);<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">&nbsp;<\/FONT><\/SPAN><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">which creates the task to wrap the <\/FONT><SPAN>RenderLoop()<\/SPAN><FONT face=\"Calibri\" size=\"3\"> and supplies a <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TaskManager<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> to control the options for parallel execution.<SPAN>&nbsp; <\/SPAN>The first <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">TaskManager<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">, <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">_parallelTm<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">, will schedule one thread on every core of the machine, whereas <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">_sequentialTm<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> only uses one thread on one core in order to simulate a simple sequential implementation.<SPAN>&nbsp; <\/SPAN>Actually, each of these variables is actually a <\/FONT><SPAN>LazyInit<\/SPAN><SPAN>&lt;<SPAN>TaskManager<\/SPAN>&gt; <\/SPAN><FONT face=\"Calibri\" size=\"3\">which ensure creation of the main type only if the variable is used.<SPAN>&nbsp; <\/SPAN>This is a minor usage of <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">LazyInit&lt;T&gt;<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"> 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\u2019ll never instantiate the parallel TaskManager.<SPAN>&nbsp; <\/SPAN>Keep this handy construct in mind for objects that might go unused.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\"><\/FONT><\/FONT>&nbsp;<\/P>\n<P class=\"MsoNormal\"><SPAN><FONT size=\"3\"><FONT face=\"Calibri\">The code for handling the &#8220;stop-animation&#8221; action includes the following:<\/FONT><\/FONT><\/SPAN><\/P>\n<P class=\"MsoNormal\"><SPAN><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">_renderTask.ContinueWith(<SPAN>delegate<\/SPAN><\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">{<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>BeginInvoke((<SPAN>Action<\/SPAN>)<SPAN>delegate<\/SPAN><\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>{<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>chkParallel.Enabled = <SPAN>true<\/SPAN>;<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>chkShowThreads.Enabled = chkParallel.Checked;<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>btnStartStop.Enabled = <SPAN>true<\/SPAN>;<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>btnStartStop.Text = <SPAN>&#8220;Start&#8221;<\/SPAN>;<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>});<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">});<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>_renderTask.Cancel();<\/SPAN><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">This sets a continuation-handler for the task that is wrapping the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">RenderLoop()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">, and this continuation cleans up the GUI and re-enables various controls.<SPAN>&nbsp; <\/SPAN>Notice that we must use <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">MainForm.BeginInvoke()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> in order to run the clean-up code on the GUI thread, as tasks run on a background worker thread.<SPAN>&nbsp; <\/SPAN>After the cleanup continuation is registered, we call <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Task.Cancel()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">.<SPAN>&nbsp; <\/SPAN>Notice that the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">RenderLoop()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> is checking for <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">t.IsCanceled<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> in order to detect the cancellation and co-operatively bail out of its animation loop.<SPAN>&nbsp; <\/SPAN>The standard overload for <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Task.ContinueWith()<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"><SPAN>&nbsp; <\/SPAN>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.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"Codei\"><FONT face=\"Calibri\" size=\"3\">There is an interesting system used for managing the bitmaps used for rendering.<SPAN>&nbsp; <\/SPAN>In particular, allocation of the image bitmaps is expensive, but we don\u2019t want to have to wait for the GUI to display a bitmap before we start computation of the next.<SPAN>&nbsp; <\/SPAN>One way to solve this is a classic double-buffered solution with one bitmap for scene-drawing and another that is ready for <I>blitting<\/I> to the screen (this was the approach taken in the sample included with the December 2007 CTP).<SPAN>&nbsp; <\/SPAN>A more general solution is to keep rendering images at the maximum rate and add them to a queue for blitting.<SPAN>&nbsp; <\/SPAN>This solution has been implemented by using a set of bitmaps for drawing, and each is sent for blitting by calling <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">Form.BeginInvoke()<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\">with an appropriate delegate. <SPAN>&nbsp;<\/SPAN>In order to reuse bitmaps rather than creating and disposing them repeatedly, an <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">ObjectPool&lt;T&gt;<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> (see ObjectPools.cs) has been built around a <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">ConcurrentQueue&lt;T&gt;<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> that supports object reuse and creation of new objects if no reusable ones are available.<SPAN>&nbsp; <\/SPAN>The <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">ConcurrentQueue&lt;T&gt;<\/FONT><\/SPAN><\/SPAN><FONT face=\"Calibri\" size=\"3\"> is particularly useful as it provides all the machinery required to make the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">ObjectPool&lt;T&gt;<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"> thread-safe.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">The C# ray tracer has been ported to Visual Basic and F#, including all of the items discussed above except for image colorization.<SPAN>&nbsp; <\/SPAN>To build and run the F# version, download the F# languge support pack from <\/FONT><A href=\"http:\/\/research.microsoft.com\/fsharp\/fsharp.aspx\"><FONT face=\"Calibri\" size=\"3\">http:\/\/research.microsoft.com\/fsharp\/fsharp.aspx<\/FONT><\/A><FONT size=\"3\"><FONT face=\"Calibri\">. (To compile the sample, if you\u2019re running on x64, you\u2019ll need to modify the project settings to point to System.Core.dll in the correct location, as it\u2019s 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:<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\">member this.RenderToArrayParallel(scene, rgb : int[]) = <\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>Parallel.For(0, screenHeight, fun y -&gt; <\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>let stride = y * screenWidth<\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>for x = 0 to screenWidth &#8211; 1 do <\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>let color = TraceRay ({Start = scene.Camera.Pos; Dir = GetPoint x y scene.Camera }, scene, 0)<\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>let intColor = color.ToInt ()<\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>rgb.[x + stride] &lt;- intColor)<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">Finally, a completely different ray tracer implementation is shown in Samples\\LINQRayTracer.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">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.<SPAN>&nbsp; <\/SPAN>The original query was written in the form:<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>from<\/SPAN><SPAN> y <SPAN>in<\/SPAN> <SPAN>Enumerable<\/SPAN>.Range(0, screenHeight)<\/SPAN><\/FONT><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp; <\/SPAN>\u2026<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN><SPAN>&nbsp;&nbsp; <\/SPAN>select<\/SPAN><SPAN> <SPAN>from<\/SPAN> x <SPAN>in<\/SPAN> <SPAN>Enumerable<\/SPAN>.Range(0, screenWidth)<\/SPAN><\/FONT><\/P>\n<P class=\"MsoNormal\"><SPAN><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/SPAN><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">which is a natural 2-D construct to loop over each pixel in each row.<SPAN>&nbsp; <\/SPAN>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:<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN>from<\/SPAN><SPAN> y <SPAN>in<\/SPAN> <SPAN>Enumerable<\/SPAN>.Range(0, screenHeight).<B><I>AsParallel()<\/I><\/B><\/SPAN><\/FONT><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp; <\/SPAN>\u2026<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><FONT face=\"Courier New\"><SPAN><SPAN>&nbsp;&nbsp; <\/SPAN>select<\/SPAN><SPAN> <SPAN>from<\/SPAN> x <SPAN>in<\/SPAN> <SPAN>Enumerable<\/SPAN>.Range(0, screenWidth)<\/SPAN><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT size=\"3\"><FONT face=\"Calibri\">This sets the query to use PLINQ to partition the work of outer query over all the available cores.<SPAN>&nbsp;&nbsp; <\/SPAN>The other adjustment is to enumerate the query via <\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">pixelsQuery.ForAll(row =&gt;<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">{<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN><SPAN>foreach<\/SPAN> (<SPAN>var<\/SPAN> pixel <SPAN>in<\/SPAN> row)<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>{<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>rgb[pixel.X + (pixel.Y * screenWidth)] = pixel.Color.ToInt32();<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>}<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN><SPAN>int<\/SPAN> processed = <SPAN>Interlocked<\/SPAN>.Increment(<SPAN>ref<\/SPAN> rowsProcessed);<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN><SPAN>if<\/SPAN> (processed % rowsPerUpdate == 0 ||<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\"><SPAN>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/SPAN>processed &gt;= screenHeight) updateImageHandler(rgb);<\/FONT><\/SPAN><\/P>\n<P class=\"Code\"><SPAN><FONT face=\"Courier New\">});<\/FONT><\/SPAN><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">which causes the query to run to completion in parallel.<SPAN>&nbsp; <\/SPAN>Notice that the per-row worker delegate includes thread-safe access to the <\/FONT><SPAN class=\"Code-inlineChar\"><SPAN><FONT face=\"Courier New\">rowsProcessed<\/FONT><\/SPAN><\/SPAN><FONT size=\"3\"><FONT face=\"Calibri\"> counter to be safe in concurrent execution.<\/FONT><\/FONT><\/P>\n<P class=\"MsoNormal\"><FONT face=\"Calibri\" size=\"3\">&nbsp;<\/FONT><\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The June 2008 Community Technology Preview (CTP) of Parallel Extensions to the .NET Framework was released on Monday, and we\u2019re really pleased at the level of excitement in the community that we\u2019re seeing in response.&nbsp; As part of the CTP, we included a &nbsp;variety of demos and samples to help provide a tour of the [&hellip;]<\/p>\n","protected":false},"author":482,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[7908],"tags":[7911,7916,7909,7910,7912],"class_list":["post-2603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pfxteam","tag-code-samples","tag-coordination-data-structures","tag-parallel-extensions","tag-plinq","tag-task-parallel-library"],"acf":[],"blog_post_summary":"<p>The June 2008 Community Technology Preview (CTP) of Parallel Extensions to the .NET Framework was released on Monday, and we\u2019re really pleased at the level of excitement in the community that we\u2019re seeing in response.&nbsp; As part of the CTP, we included a &nbsp;variety of demos and samples to help provide a tour of the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/482"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=2603"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/2603\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=2603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=2603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=2603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}