There is no escaping from concurrency challenges... or is there?
(A slightly modified version of this article was published in the August 2008 edition of the MSDN Flash newsletter)
Dual, quad, and eight-core processors are becoming the norm. Is your application capable of utilising all available processors? In order to achieve this level of utilisation on an n-processor machine, an application ideally needs at least n threads concurrently performing operations.
Although writing multi-threaded applications has become simpler over the years, many still find it challenging. Also many of the constructs such as the .NET ThreadPool have deficiencies that make them less suitable as the manycore shift begins to accelerate.
Over the past few years, Microsoft has been hard at work developing a new set of parallel extensions for .NET, aptly named Parallel Extensions to the .NET Framework. One of the additions is a set of lightweight and scalable thread-safe data structures and synchronization primitives such as a concurrent dictionary and a spin lock.
It also includes an implementation of LINQ-to-Objects that automatically executes queries in parallel, scaling to utilise most or all of the available processors without developers explicitly managing the distribution of work across all processors. This technology is called Parallel LINQ or PLINQ and the query syntax is almost identical to that of LINQ-to-Objects.
var q = from c in customers.AsParallel()
join r in regions on c.RegionID equals r.RegionID
where c.City == "London" && r.Name == "Kingston"
select c;
When a repetitive computation can be parallelised, the Parallel Extensions to the .NET Framework offers a few interesting data-oriented operations such as For and ForEach that execute a loop in which iterations may run in parallel on parallel hardware. For example the following classic foreach loop can easily be converted to a parallel foreach:
|
Sequential execution |
è |
foreach (var c in formulae)
Calculate(f);
|
|
Possible parallel execution |
è |
Parallel.ForEach(formulae, f => Calculate(f)); |
The actual parallelisation of actions is managed by the Task Parallel Library (TPL) that provides an abstraction layer on top of raw threads. TPL uses the notion of Task that is the smallest unit of work and could potentially be executed by any thread owned by TPL. Therefore correctly identifying tasks that could be executed in parallel is crucial. It is then the job of the scheduler component of TPL to decide whether those tasks should execute sequentially or in parallel. This decision is usually made based on available system resources and possible user preferences.
// Create a task to call Calculate(object o) and schedule it for execution
Task t = Task.Create(Calculate);
// Other activities...
// Wait for this task to complete
t.Wait();
Developing concurrent applications requires a shift in mindset. For example, only a single exception can be thrown at any one time when sequentially executing a for loop. However executing the same loop in parallel may warrant the need for dealing with multiple concurrent exceptions. There are also a few parallelism blockers that should be avoided if you are planning to benefit from Parallel Extensions to the .NET Framework when it is released.
There is a lot of promise in Parallel Extensions. If you want to find out more, I’d encourage you to download the June 2008 Community Technology Preview build.
As you are probably aware, one of the new additions to the .NET Framework 3.5 SP1 is a technology called ADO.NET Data Services (code name Astoria). ADO.NET Data Services natively supports ADO.NET Entity Framework (EF) models. However Data Services it is not limited to EF.
ADO.NET Data Services can deploy consistent representations of data regardless of the underlying data source. This approach has made CLR-based data models first class citizens. See here for a comprehensive guide on using CRL-based data models.
Imagine the following class diagram that represents two entities:
As you can see, Library has a collection of Books. Therefore Library.Books can be considered a one-to-many resource navigation link to a collection of Books.
public class Library
{
public int LibraryID { get; set; }
public string LibraryName { get; set; }
public List<Book> Books { get; set; }
}
public class Book
{
public int BookID { get; set; }
public string BookTitle { get; set; }
}
A simple Data Services’ resource container exposing a list of libraries may look similar to the following:
public class LibraryDataModel
{
static List<Library> s_libraries = ...;
public IQueryable<Library> Libraries
{
get
{
return s_libraries.AsQueryable();
}
}
}
Unfortunatly exploring this data model – by perhaps browsing to the URI that exposes this model – may fail throwing an exception similar to the following:
Request Error: The server encountered an error processing the request. The exception message is 'The property 'Books' on type 'AstoriaWeb.Library' is not a valid property. Properties whose types are collection of primitives or complex types are not supported.'
This means that ADO.NET Data Services was not able to automatically consider Books as a resource set that can be referenced using resource navigation links from Library resources. In fact, without some more information, it is really hard for Data Services to automatically expose a new resource set through a resource container.
So how can you avoid this? For this release of Data Services at least, you need to explicitly expose Books as a resource set in the resource container:
public class LibraryDataModel
{
static List<Library> s_libraries = ...;
static List<Book> s_books = ...;
public IQueryable<Library> Libraries
{
get
{
return s_libraries.AsQueryable();
}
}
public IQueryable<Book> Books
{
get
{
return s_books.AsQueryable();
}
}
}
This article was written based on .NET Framework 3.5 SP1 Beta.
Not sure about you but I was not aware of the existence of the DebuggerStepThroughAttribute. Debugging code can be difficult at times and any tool or mechanism that can ease this pain is always welcome.
As far as the CLR is concerned, there is no semantic attached to this attribute. However Visual Studio does not step through methods or classes that are decorated with this attribute. Although you could still use breakpoints in those methods or classes, they are never hit.
And here is how breakpoints would look in Visual Studio 2008:
This attribute can be applied to methods, property accessors, classes and structs. I found it to be extremely useful when I wanted to step through a method without first stepping through all property accessors used as parameters or the source instance of the method. In the example below, a.Value and b.Value are not stepped through when pressing F11 in Visual Studio. It is only the Add method that is fully debugged:
var a = new SomeValue(10);
var b = new SomeValue(150);
...
Add(a.Value, a.Value);
class SomeValue
{
...
public int Value
{
[DebuggerStepThrough]
get { return value; }
}
}
Enjoy!
When using a WebChannelFactory inside a WCF service that already has an OperationContext, you may need to create a new context before being able to successfully callout using a channel created by the WebChannelFactory. (Notice the line in bold)
public class RelationService : IRelationService
{
public Relation[] GetRelations()
{
var factory = new WebChannelFactory<ICustomerService>(
new Uri("http://localhost/customerservice/customers.svc"));
var proxy = factory.CreateChannel();
using ((IDisposable)proxy)
using (new OperationContextScope((IContextChannel)proxy))
{
var customers = proxy.GetCustomers();
return customers.Select(c => new Relation(c.Name, c.Age)).ToArray();
}
}
}
In the above example, GetRelations() is a RESTful service operation calling into another RESTful service located at the Uri shown above.

Without using the new context, you may get an exception similar to the following:
ProtocolException: The remote server returned an unexpected response: (405) Method Not Allowed.
When investigating further, you may notice that WCF could be using an incorrect HTTP verb for communicating with the service that exposes the GetCustomers() operation.
As it happens, here is how ICustomerService service contract looks like:
[ServiceContract]
public interface ICustomerService
{
[OperationContract]
[WebGet(
UriTemplate = "/customers",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare
)]
List<Customer> GetCustomers();
}
As you can see it is expecting the GET verb. Without creating a new context, WCF ends up using the POST verb which will eventually cause the above exception.
This is an article in a series of blog entries describing a set of new Coordination Data Structures (CDS) introduced in the June 2008 CTP of the Parallel Extensions for .NET Framework.
In C#, when a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class:
readonly Company _company = new Company();
The assignment window is limited to the constructor or the declaration. In many applications however, it is desirable to have the readonly behaviour (set once and read many times) without this limitation. As you might have guessed, the Parallel Extensions now provides a type (System.Threading.WriteOnce<T>) for this exact purpose.
WriteOnce<T> exposes a Value property that can only be set once. This is obviously done in a thread-safe manner:
// this is a struct, so it will not require an explicit construction
WriteOnce<Guid> wo;
wo.Value = Guid.NewGuid();
As you would expect, attempting to reassign the Value property will throw an exception (“The variable is already initialized”):
WriteOnce<T> is a thread-safe type so if trying to set the Value property concurrently, one of the setters will throw the above exception. In order to avoid this, use the TrySetValue method instead:
WriteOnce<Guid> wo;
if (wo.TrySetValue(Guid.Empty))
{
// the value was set successfuly
}
Attempting to access the Value of a WriteOnce<T> before it has been set invalidates the WriteOnce<T> instance for all future access. The instance will be corrupt and can no longer be accessed for future gets and set.
It corrupts the instance because there is a race condition that leads to a read before the write. Proper synchronization should be used to ensure that this race cannot happen. Therefore always ensure that the value is set before accessing it. When you are not certain if the Value is set, you can access it through the TryGetValue. This will return default(T) if the value is not set and will not corrupt the state of the instance for future use:
Guid val;
if (wo.TryGetValue(out val))
{
// the value has been set previously
}
Please note that WriteOnce<T> is a value type (struct), and as such, you need to be careful about access patterns. If you accidentally make a copy of the struct, you’ll be copying by value meaning that you will be using a replica rather than the original. For example in the code below, both assignments to what might appear as the same WriteOnce instance are allowed. The reality is however that wo1 and wo2 are two different instances:
WriteOnce<Guid> wo1;
Task.Create(
s =>
{
WriteOnce<Guid> wo2 = (WriteOnce<Guid>)s;
// assignment (1)
wo2.Value = Guid.NewGuid();
Console.WriteLine(wo2.Value);
}
, wo1);
// assignment (2)
wo1.Value = Guid.NewGuid();
In the example below however, it will not be possible to assign to wo2.Value (assignment 2 will fail). Although wo2 is a replica copy of wo1, internally it is referencing the same value object assigned in (1) which is not cloned:
WriteOnce<Guid> wo1;
// assignment (1)
wo1.Value = Guid.NewGuid();
Task.Create(
s =>
{
WriteOnce<Guid> wo2 = (WriteOnce<Guid>)s;
// assignment (2)
wo2.Value = Guid.NewGuid();
}
, wo1);
(Thanks to Joe Duffy, Ed Essey and Stephen Toub for their inputs and support)
This is an article in a series of blog entries describing a set of new Coordination Data Structures (CDS) introduced in the June 2008 CTP of the Parallel Extensions for .NET Framework.
Waiting on locks usually result in a thread context switch and associated kernel transition which at times can be considered costly. On a multi-processor machine, often it might be more efficient to busy wait for a short period of time instead of paying the cost of performing an expensive context switch and a possible transition to kernel mode.
One approach to busy waiting is to wait in a loop repeatedly checking until the lock becomes available. These types of locks are called spin-locks.
System.Threading.SpinLock provides a mutual exclusion lock primitive where a thread trying to acquire the lock waits in a loop repeatedly checking until the lock becomes available.
When acquiring a spin-lock, it uses the CompareExchange interlocked operation to ensure that the owner of the lock is assigned in a thread-safe manner (this implementation detail is subject to change):
if(Interlocked.CompareExchange(ref _owner, newOwner, owner) == owner && ...)
Failing to become the owner of the lock, other threads will wait using a SpinWait until the lock is released (pseudo code):
public void Enter()
{
SpinWait sw = new SpinWait();
...
while (true)
{
if (!IsOwnerSet())
{
// set the owner - atomic
if (SetOwner())
{
// this thread is the owner so return
return;
}
}
// spin wait once
sw.SpinOnce();
}
...
}
One point to mention here is the effect of a spin-lock on a single-processor machine. On these systems, the spin-lock will hamper the performance by adding an unnecessary delay into the whole process. It will not result in a deadlock because after executing its quantum, the spinning thread is context-switched or pre-empted by another thread, however the time spent looping has not been productive.
Due to this behaviour, the System.Threading.SpinLock primitive ensures we always yield (switch threads) on single-processor machines instead of using busy waits.
Unlike Monitor, SpinLock publicly offers a set of reliable enter methods for acquiring a lock (i.e. ReliableEnter and TryReliableEnter). You should probably never use the unreliable enter methods because in the case of any asynchronous exceptions such as ThreadAbortException and OutOfMemoryException, you may end up with an orphaned lock that is never released. This is particularly true in ASP.NET since it uses aborts very aggressively.
|
As a side-note, you may wonder how we achieve this reliability. As it happens, the default CLR host postpones async exceptions inside a finally block until the end of the block. Therefore any part of the code that could result in an orphaned lock can be included inside a finally block:
try
{
}
finally
{
// take the lock in here
// ...
|
Closer investigating of the SpinLock.Exit method reveals an overload that takes a Boolean. If this Boolean is set to true, SpinLock flushes the write buffers associated with the lock in order to ensure that all processors are immediately made aware that the lock is now available. This is more expensive but will prevent a situation where one processor is given an unfair advantage to reacquire the lock:
SpinLock sharedLock = new SpinLock();
while (true)
{
sharedLock.Enter();
sharedLock.Exit();
// very little between Exit and retry Enter;
// possibly no other processor would see the lock available!
}
There are a few more things to remember when using the SpinLock:
1- When using the default constructor, the thread that owns the lock can enter the same lock and effectively cause a deadlock:
SpinLock l = new SpinLock();
l.Enter(); // non-blocking call
l.Enter(); // blocking call
2- When using the default constructor, any thread can release the lock (This is not a recommended practice and should be avoided in normal circumstances):
SpinLock l = new SpinLock();
l.Enter();
ThreadPool.QueueUserWorkItem(delegate
{
l.Exit();
});
3- In the current implementation, you can change the above behaviour. Simply set the isThreadOwnerTrackingEnabled parameter to true when creating a new instance of SpinLock:
Setting isThreadOwnerTrackingEnabled to true changes the behaviour of the lock by:
- Prohibiting the owner thread from trying to enter the same lock – throws a LockRecursionException; and,
- Ensuring the Exit method is only called by the owner thread – a SynchronizationLockException is thrown otherwise
Something else that’s worth mentioning is that SpinLock is a struct, and as such, you need to be careful about access patterns. If you accidentally make a copy of the struct, you’ll be copying by value meaning that you will be using a replica rather than the original lock. For example in the code below, both the main thread and the ThreadPool thread would successfully enter the lock. The morale of the story is that ideally these are not passed around, and instead they are used as local variables or member fields:
SpinLock sl = new SpinLock();
ThreadPool.QueueUserWorkItem(state =>
{
SpinLock theLock = (SpinLock)state;
theLock.Enter();
}, sl);
sl.Enter();
(Thanks to Stephen Toub, Joe Duffy and Ed Essey for their input and support)
This is an article in a series of blog entries describing a set of new Coordination Data Structures (CDS) introduced in the June 2008 CTP of the Parallel Extensions for .NET Framework.
LazyInit<T> provides support for several common patterns of lazy initialization. In here we will explore some of those patterns, but first a point or two regarding lazy initialization:
- Lazy initialization is often used when the initialization process is an expensive activity which is not always required. With this approach, the execution of the initialize procedure is deferred to immediately before when it is required.
- In order to improve the start-up performance of an application, one may decide to defer some of the initialization activities.
The first pattern covered by LazyInit<T> is the optimistic lazy instantiation pattern. In this pattern, multiple instances of T may be created but only one of those instances is published for all threads to access. In pseudo code, the implementation of such structure may look similar to this:
public class Singleton
{
static volatile Singleton _instance;
private Singleton()
{
// stuff ...
}
public static Singleton Instance
{
get
{
if (_instance == null)
{
Singleton local = new Singleton();
if (Interlocked.CompareExchange<Singleton>(
ref _instance, local, null) != null)
{
IDisposable disposable = local as IDisposable;