The Visual Studio 2010 and .NET Framework 4.0 CTP is now available, featuring Parallel Extensions to .NET! Parallel Extensions has been introduced before, but what sets this CTP apart from the previous two is that it’s not a CTP of Parallel Extensions alone but of Visual Studio 2010 and .NET 4.0. And excitingly, the Task Parallel Library, PLINQ, and Coordination Data Structures have made their way deep into the heart of the Framework.
What’s New in the Task Parallel Library?
As with all of Parallel Extensions, the most important change for the Task Parallel Library is that it’s now part of the .NET Framework, and specifically it’s part of mscorlib.dll. This means that every .NET application has access to TPL, without needing to add any additional assembly references.
There are a variety of additional changes in this CTP, some more noticeable than others. One of the repeated pieces of feedback we received on our previous CTPs was that the Create factory method for initializing and scheduling tasks was lacking, both in that the name didn’t convey the full meaning of its functionality as well as that it didn’t allow tasks to be created separately from being scheduled. In this CTP, we’ve addressed that in two ways. First, we’ve renamed the Create static methods to StartNew, and second, we’ve added public constructors and an instance Start method.
Other API changes will also be visible. Task now exposes more information about its lifecycle through its Status property, which returns a TaskStatus that denotes whether the task has been created, scheduled for execution, is waiting for its child tasks to complete, has completed due to cancellation, and so on. TaskStatus includes three final states, one representing a successful completion, one representing a completion due to an unhandled exception, and one representing a completion due to cancellation. This latter status is also available through the IsCanceled property, which represents a change in semantics from the previous CTP, where IsCanceled represented whether the Cancel method had been called but at which point the task could still be executing; that information is now available through the IsCancellationRequested property.
One important change since the last CTP has to do with unhandled exceptions. The Task class needs to catch unhandled exceptions thrown out of a task’s delegate so that these exceptions can be marshaled out through a call to Wait. However, in doing so, these exceptions may go unnoticed. To address that issue, the Task Parallel Library now tracks whether unhandled exceptions have been observed, such as through a call to Wait on a Task that threw an unhandled exception. If a Task that completed due to an unhandled exception is garbage collected with its unhandled exception never having been observed, at that point the exception will be allowed to propagate, tearing down the application as would have happened had the exception been allowed to propagate when initially thrown.
A variety of implementation details have also changed in this release. For example, the system is now able to detect when tasks block on synchronization primitives and can respond by increasing the concurrency level in order to make forward progress.
You may also note that some new delegates have been introduced, namely System.Threading.Action2 and System.Threading.Func2. These are only temporary and are serving a purpose specific to this CTP release; these delegates are planned for removal in the future, replaced in usage by the existing System.Action and System.Func delegates.
What’s New in PLINQ?
PLINQ is now in System.Core.dll, together with its sequential counterpart LINQ-to-Objects.
AsSequential has been renamed to AsMerged to reflect the behavior of parallelism a little more clearly. In the system, AsParallel tells the system to partition data for parallelism and AsMerged tells PLINQ when to merge the partitions and transition to sequential LINQ-to-Objects.
There is also an overload of AsMerged that takes the System.Linq.ParallelMergeQueryOptions enumeration. This enumeration has options to hint at how elements should be yielded from PLINQ execution. FullyBuffered optimizes for whole query performance, by buffering the entire contents of the query before yielding. NotBuffered minimizes the time it takes for a produced element to be yielded to the consumer thread. AutoBuffered is the default, it buffers data and yields those in chunks to a consumer.
Additionally, some improvements have been made around reliability. This includes removal of deadlocks when exceptions are thrown from delegates.
What’s New in Coordination Data Structures?
In the June 2008 CTP, we introduced a set of coordination data structures that complement PLINQ and the Task Parallel Library. These data structures include a set of thread-safe and scalable collections as well as higher-level and specialized synchronization primitives for coordination in multithreaded applications and components. In this CTP, we’ve introduced a few changes.
The largest changes are the addition of System.Collection.Concurrent.ConcurrentDictionary<T> and System.Threading.Barrier. The former is a thread-safe and scalable hash map, while the latter is an abstracted synchronization pattern popular in parallel algorithms. In addition to these new types, we’ve augmented some existing APIs, such as provided additional constructors and methods to LazyInit<T> and updating the SpinLock type to support its Enter and Exit methods being used within constrained execution regions. Finally, this release sees a plethora of naming changes, including renaming the System.Threading.Collections namespace to System.Collections.Concurrent and renaming the IConcurrentCollection<T> interface to IProducerConsumerCollection<T>.