LP on .NET

August 25, 2009

Documenting Thread Safety

Filed under: .NET,C#,Microsoft,Software Development — Larry Parker @ 7:10 am

I have found that developers (including myself) typically write code to be thread-safe only when needed, as opposed to proactively making code thread-safe.  This is understood because writing thread-safe code is not always easy, especially when dealing with instance members.  Just look at the MSDN documention, and you’ll find the following disclaimer under most classes in the Thread Safety section:

Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

But once code has been written to be thread-safe, it’s often not very well documented as such.  When the code is revisited months (or even years) later, it’s not immediately evident if the code is thread-safe, or what measures were taken to make it thread-safe.

Taking a cue from a book I recently read on concurrency (Java Concurrency in Practice — see my blog post as well), I have created a few attributes that can be used to decorate your code to help document thread safety.

Attributes can be very helpful with documentation because they help enforce consistency, and can also be read programatically.  For example, we could write a utility that uses reflection to display all classes in an assembly that have been marked as thread-safe.

Before I insert the code that defines the attributes, I’ll give a quick example showing how they might be used.

I recently wrote a file synchronization utility that syncs up files across the public Internet.  Client machines periodically take snapshots of the folders under sync management and send them to the server, at which time the server compares these with its own recent snapshot.  In order to reduce I/O requirements on the server, snapshots of the server’s source folder are taken periodically via a timer and cached.  The timer fires on a thread from the thread pool, and the service calls are processed (via WCF) on threads from the thread pool as well.  Therefore, there’s definitely some concurrency going on, and the code needs to be thread safe.

The following is an excerpt from the File Sync Snapshot Manager class:

[ThreadSafe]
public class FileSyncSnapshotMgr
{
    // ...

    [Guards("_lastSnapshot, _lastDiff")]
    private Object _syncObj = new Object();

    [GuardedBy("_syncObj")]
    private FileSyncSnapshot _lastSnapshot;

    /// <summary>
    /// Gets the last snapshot stored in cache.
    /// </summary>
    public FileSyncSnapshot LastSnapshot
    {
        get { lock (_syncObj) return _lastSnapshot; }
    }

    [GuardedBy("_syncObj")]
    private FileSyncDiff _lastDiff;

    /// <summary>
    /// Gets the last snapshot diff stored in cache.
    /// </summary>
    public FileSyncDiff LastDiff
    {
        get { lock (_syncObj) return _lastDiff; }
    }

    // ...
}

Looking at the code, we see a few things.  The class is marked as thread-safe with the ThreadSafe attribute.  This is just an attribute for documentation purposes and doesn’t have any effect on the code.  But it tells us that someone marked the class as thread-safe, so we assume (or at least hope!) that the class is indeed thread-safe for its intended use.

We can also tell, by looking at the Guards attribute, that our _syncObject field guards the _lastSnapshot and _lastDiff fields.  Conversely, by looking at the GuardedBy attribute, we can quickly identify the sync object that guards a field.

In the case where a field is both the synchronization object and the object it guards, I use the text “self” to designate this.  For example:

[GuardedBy("self")]
private Queue<PackageCreationRequest> _packageCreationRequests =
    new Queue<PackageCreationRequest>();

None of this is very complicated, but I have found that some simple documentation can go a long way.  The hope is that when you (or another developer) revisits the code, that it will be easier to understand the intention behind what was done to make the code thread-safe.

The following is the code that defines the attributes.  Hope this helps.

/// <summary>
/// Represents an attribute that marks a class as thread-safe.
/// This is only for documentation purposes and does not
/// have any affect on the code's actual thread-safety.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class ThreadSafeAttribute : Attribute
{
}

/// <summary>
/// Represents an attribute that marks a class as not being thread-safe.
/// This is only for documentation purposes and does not
/// have any affect on the code's actual thread-safety.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class ThreadUnsafeAttribute : Attribute
{
}

/// <summary>
/// Indicates the synchronization object that guards this item.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class GuardedByAttribute : Attribute
{
    /// <summary>
    /// Initializes a new <see cref="GuardedByAttribute"/> object
    /// and sets the <see cref="SyncObjectName"/> property.
    /// </summary>
    /// <param name="syncObjectName">The name of the sync object.</param>
    public GuardedByAttribute(String syncObjectName)
    {
        SyncObjectName = syncObjectName;
    }

    /// <summary>
    /// Gets or sets the name of the synchronization object that guards this item.
    /// </summary>
    public String SyncObjectName { get; set; }
}

/// <summary>
/// Indicates the items that this synchronization object guards.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class GuardsAttribute : Attribute
{
    /// <summary>
    /// Initializes a new <see cref="GuardsAttribute"/> object
    /// and sets the <see cref="Items"/> property.
    /// </summary>
    /// <param name="syncObjectName">The name of the sync object.</param>
    public GuardsAttribute(String items)
    {
        Items = items;
    }

    /// <summary>
    /// Gets or sets a comma-separated list of items guarded by this synchronization object.
    /// </summary>
    public String Items { get; set; }
}

Advertisements

August 12, 2009

Free Online Book about Threading in C#

Filed under: .NET,C#,Software Development — Larry Parker @ 6:17 am

I just came across a free online book about threading in C# on www.albahari.com.  The main page is here and you can download the entire PDF here.

The online book is a bit different from Chapter 19 (Threading) from the book C# 3.0 in a Nutshell, although I’m not sure if this was written before or after the book.

The topic of threading is broken down into four sections in the online book:

  • Getting Started (overview and concepts)
  • Basic Synchronization (e.g. locking, thread safety, and wait handles)
  • Using Threads (e.g. thread pooling, and timers)
  • Advanced Topics (e.g. non-blocking synchronization, and wait and pulse)

Lots of good threading examples and discussions, and well worth checking out.

August 11, 2009

Keeping Remoting Objects Alive

Filed under: .NET,C#,Software Development — Larry Parker @ 9:15 pm

I’m currently writing a test utility to simulate multiple clients hitting a server.  There’s a simple UI that shows what’s going on, but the interesting and useful part are the client objects all running side-by-side without interfering with each other.

This is accomplished by running each client in its own application domain.  When the user initiates a client action from the UI, remoting is used to communicate with the client object in the appropriate app domain.

Everything was working great, and I was pleased with my simulator.  It’s certainly easier to run (and debug!) 10 simulators in a single test utility than having to fire up 10 separate instances of the utility app.

However, after a few minutes when I again initiated a client action from my UI, I got the following dreadful error:

RemotingException

After staring at this for a few seconds, I recalled reading the chapter on app domains in the book C# 3.0 in a Nutshell.  The problem is that remoting objects are leased, and if a leasing interval is left unspecified, the .NET runtime drops the object after about 5 minutes.

One solution is to have your remoting object (i.e. the object that descends from MarshalByRefObject) override the InitializeLifetimeService method and return null.  This tells the CLR to keep the object around for as long as the consumer needs it.

Here’s what the code looks like:

public class MyTestClient : MarshalByRefObject, IMyTestClient
{
    public override object InitializeLifetimeService()
    {
        // Tell the runtime to keep the object around
        return null;
    }
    // etc.

There are other ways to better control the object’s lease, but for my purposes this works great since the consumer of the remoting objects are in the default app domain and are alive for the duration of the utility.

I’m sure there are better discussions of this on MSDN and blogs, but if you encounter the above error, this is one way to solve it.

Hope this helps.

August 1, 2009

Let’s Hear it for Blogging

Filed under: .NET,Blogroll,C#,Visual Studio — Larry Parker @ 11:06 am

I recently ran into that darn Visual Studio bug that I got a few weeks ago:

API restriction: The assembly ‘file:///C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll’ has already loaded from a different location. It cannot be loaded from a new location within the same appdomain

Of course I couldn’t remember what the fix was.  Fortunately I blogged about it and found the answer here (the fix once again was to delete my solution’s user options file).

I guess that’s what technical blogging is all about – keeping a running record of what you encounter in your programming travels.  Let’s hear it for blogging!  🙂

Blog at WordPress.com.