Threading – understanding the volatile modifier in C#

Whilst working on Bingo.Net I have come across a number of concurrency issues which must be fairly common in synchronous multiplayer games. During my attempts to overcome these obstacles I came across the volatile modifier in C# which at first glance looked like a silverbullet for all concurrency problems, but under closer inspection it more closely resembles a false dawn and is catered for a far more cornered use case…

Before we start, let’s first take a look at the definition of the volatile modifier on MSDN:

Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times.

In other words, by simply marking a field with the volatile keyword, we can be sure that we will always get the latest value of that field wherever we ask for it! Sounds too good to be true? That’s because it is.

The true face of the volatile modifier

Whilst MSDN’s definition is correct it’s certainly misleading. What the volatile modifier gives you is protection against concurrency issues arising from multiple threads executing on multiple CPUs caching data and re-ordering instructions. Now let’s take a closer look at each case:

Data Caching

As Jon Skeet pointed out in his article (see references section), memory in modern computers is complex, with multiple levels of caching, processor registers and multiple processors sharing main memory but possibly not caches, etc. A processor might cache a piece of data from the main memory and use the cached data in the execution of a thread, modify it, and only update the main memory at a later time. During which time another thread running concurrently on another CPU might have read the same bit of data from main memory and used the outdated version of the data, i.e.:

image

Marking a field as volatile would make sure that it is not cached during the execution of a thread.

Compiler Optimization

The .NET compiler is allowed to alter the order of reads and writes in any way which does not change the meaning of the original program. For example, as pointed out in Dr Dobb’s articled (see reference section) it’s legal for the compiler to transform:

a = 1;  // A

a = 2;  // B

to:

// A’ – eliminate line A

a = 2;  // B

This is legal because the semantic of the original program is preserved. SImilarly:

a = 1;          // C – write to a

local = a;  // D – read from a

to

a = 1;          // C – write to a

local = 1;  // D’ – apply “constant propagation”

This reordering is also legal according to the rules of the compiler. However, it’s easy to see how this can be a problem in a multi-threaded environment where another thread is writing to a concurrently.

Pitfalls

It’s easy to be lured into a false sense of security by the volatile keyword and think that if you’re guarantee the latest value of a field you won’t need to use lock anymore. Marking a field as volatile doesn’t prevent multiple threads from interleaving , take this code for example:

private volatile int _counter = 0;

if (_counter < 10) // guaranteed latest value of _counter
{
    // value of _counter could have been modified by another thread,
    // hence invalidating the if condition
    _counter++;
}

Also, although you’re able to use the volatile modified on reference types, only the reference (which is a 32-bit integer pointing to a location in memory) itself is volatile but not the instance values. For example, you can’t use volatile on a double because it’s 64-bit and therefore read/write operations cannot be performed atomically (in a single instruction), but you can still make a wrapper class volatile:

public class MyClass
{
    private volatile VolatileDouble _volatileDouble; // guaranteed
}

public class VolatileDouble
{
    public double Double { get; set; }  // not guaranteed
}

In this case, although you’re guaranteed the latest version of the reference pointer _volatileDouble, you’re not guaranteed the latest value of the Double property of the instance. To get around this, you will need to make the VolatileDouble type immutable so the value of its Double property cannot be changed without creating a new instance and updating the reference point _volatileDouble. However, in situations like this, it’s usually better and easier to use Interlocked.Read and Interlocked.Exchange in conjunction with BitConverter.Int64BitsToDouble and BitConverter.DoubleToInt64Bits instead.

Parting Thoughts..

Though the volatile modifier might not be the all-conquering solution to concurrency, the point to take away from here is that although code like this works most of the time:

class BackgroundTaskDemo
{
    private bool stopping = false;

    static void Main()
    {
        BackgroundTaskDemo demo = new BackgroundTaskDemo();
        new Thread(demo.DoWork).Start();
        Thread.Sleep(5000);
        demo.stopping = true;
    }

    static void DoWork()
    {
        while (!stopping)
        {
            // Do something here
        }
    }
}

it’s not guaranteed to work, and we shouldn’t rely on the right combination of compiler, runtime, JIT, the CPU and the platform to ensure the correct running of our application. This is where the volatile modifier can help.

Also, the volatile modifier can help you achieve thread-safety in some situations. Unlike the bit of unsafe code I showed earlier, where you’re modifying the value of a field based on what it is right now, which requires you to lock around it. (and everywhere else you’re using the same field!) If all you want to do is do a check against a field and then perform an action which does not require using the field again then you can get away with just making it volatile:

private volatile int _counter = 0;
if (_counter < 10) // guaranteed latest value of _counter
{
    // you're safe so long you don't reference _counter again in here, that
    // goes to any method you call from here too!
    Console.WriteLine("We're still not there yet!");
}

References:

Jon Skeet’s article on Volatility, Atomicity and Interlocking

Dr Dobb’s article on volatile in different languages

StackOverflow question on volatile vs Interlocked vs lock

StackOverflow question on using volatile and lock

StackOverflow question on using volatile on reference type holding a double

MSDN article on the volatile modifier

Thread-safe enumeration in C#

I had a problem with the project I’m working on at work where on the base class I had a list which its child classes need to have access to in a read-only capacity but manipulation to the list itself is handled by the base class only. However, the standard C# List<T> and Enumerator<T> are not thread-safe and we started seeing problems when the list is modified by one thread whilst another is trying to loop through it.

Whilst looking for a clean solution we found this article on CodeProject:

http://www.codeproject.com/KB/cs/safe_enumerable.aspx

The article had covered much of the implementation you need, but left some gaps you need to plug yourself for a thread-safe list which I have included below along with some of the useful methods you’d find on List<T>:

Thread-safe Enumerator<T>

/// <summary>
/// A thread-safe IEnumerator implementation.
/// See: http://www.codeproject.com/KB/cs/safe_enumerable.aspx
/// </summary>
public class SafeEnumerator<T>: IEnumerator<T>
{
    // this is the (thread-unsafe)
    // enumerator of the underlying collection
    private readonly IEnumerator<T> _inner;

    // this is the object we shall lock on.
    private readonly object _lock;

    public SafeEnumerator(IEnumerator<T> inner, object @lock)
    {
        _inner = inner;
        _lock = @lock;

        // entering lock in constructor
        Monitor.Enter(_lock);
    }

    public T Current
    {
        get { return _inner.Current; }
    }

    object IEnumerator.Current
    {
        get { return Current; }
    }

    public void Dispose()
    {
        // .. and exiting lock on Dispose()
        // This will be called when foreach loop finishes
        Monitor.Exit(_lock);
    }

    /// <remarks>
    /// we just delegate actual implementation
    /// to the inner enumerator, that actually iterates
    /// over some collection
    /// </remarks>
    public bool MoveNext()
    {
        return _inner.MoveNext();
    }

    public void Reset()
    {
        _inner.Reset();
    }
}

Thread-safe List<T>

/// <summary>
/// A thread-safe IList implementation using the custom SafeEnumerator class
/// See: http://www.codeproject.com/KB/cs/safe_enumerable.aspx
/// </summary>
public class SafeList<T> : IList<T>
{
    // the (thread-unsafe) collection that actually stores everything
    private readonly List<T> _inner;

    // this is the object we shall lock on.
    private readonly object _lock = new object();

    public SafeList()
    {
        _inner = new List<T>();
    }

    public int Count
    {
        get
        {
            lock (_lock)
            {
                return _inner.Count;
            }
        }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public T this[int index]
    {
        get
        {
            lock (_lock)
            {
                return _inner[index];
            }
        }
        set
        {
            lock (_lock)
            {
                _inner[index] = value;
            }
        }
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        lock (_lock)
        {
            // instead of returning an usafe enumerator,
            // we wrap it into our thread-safe class
            return new SafeEnumerator<T>(_inner.GetEnumerator(), _lock);
        }
    }

    /// <remarks>
    /// To be actually thread-safe, our collection must be locked on all other operations
    /// </remarks>
    public void Add(T item)
    {
        lock (_lock)
        {
            _inner.Add(item);
        }
    }

    public void Clear()
    {
        lock (_lock)
        {
            _inner.Clear();
        }
    }

    public bool Contains(T item)
    {
        lock (_lock)
        {
            return _inner.Contains(item);
        }
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        lock (_lock)
        {
            _inner.CopyTo(array, arrayIndex);
        }
    }

    public bool Remove(T item)
    {
        lock (_lock)
        {
            return _inner.Remove(item);
        }
    }

    public IEnumerator GetEnumerator()
    {
        lock (_lock)
        {
            return new SafeEnumerator<T>(_inner.GetEnumerator(), _lock);
        }
    }

    public int IndexOf(T item)
    {
        lock (_lock)
        {
            return _inner.IndexOf(item);
        }
    }

    public void Insert(int index, T item)
    {
        lock (_lock)
        {
            _inner.Insert(index, item);
        }
    }

    public void RemoveAt(int index)
    {
        lock (_lock)
        {
            _inner.RemoveAt(index);
        }
    }

    public ReadOnlyCollection<T> AsReadOnly()
    {
        lock (_lock)
        {
            return new ReadOnlyCollectio<T>(this);
        }
    }

    [CheckParameters]
    public void ForEach([NotNull] Action<T> action)
    {
        lock (_lock)
        {
            foreach (var item in _inner)
            {
                action(item);
            }
        }
    }

    [CheckParameters]
    public bool Exists([NotNull] Predicate<T> match)
    {
        lock (_lock)
        {
            foreach (var item in _inner)
            {
                if (match(item))
                {
                    return true;
                }
            }
        }
        return false;
    }
}
You can see I’ve used the CheckParameters and NotNull attributes for parameter validation using PostSharp, you can easily substitute them with normal null checks.

Thread-safe IEnumerable<T>

/// <summary>
/// A thread-safe IEnumerable implementation
/// See: http://www.codeproject.com/KB/cs/safe_enumerable.aspx
/// </summary>
public class SafeEnumerable<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> _inner;
    private readonly object _lock;

    public SafeEnumerable(IEnumerable<T> inner, object @lock)
    {
        _lock = @lock;
        _inner = inner;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return new SafeEnumerator<T>(_inner.GetEnumerator(), _lock);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Threading – Using ReaderWriterLockSlim

When dealing with concurrency/threading issues in .Net, the normal approach is to use lock() to lock a dedicated sync object like this:

private static readonly object padlock = new object();
…
lock(padlock)
{
     // enter critical section here
}

This is an efficient, simple and well proven way to get thread-safety in .Net and is probably all you’ll ever need in your project. However, as this approach ensures only one thread can enter the critical section at any one time it’s not ideal for managing access to a shared resource because all read and write operations must be made sequentially and this results in a performance hit on your application. Ideally all threads should be able to read the shared resource simultaneously but only one thread can update it and no other threads can read from the resource whilst the update is happening.

.Net’s answer to this used to be the ReaderWriterLock, which since .Net 3.5 has been superseded by the better, more lightweight and performing ReaderWriterLockSlim which Microsoft is recommending for all new development.

The ReaderWriterLockSlim has three modes: Read, Ungradeable and Write:

  • many threads can enter Read lock simultaneously
  • only one thread can enter Ungradeable lock but other threads can still enter Read lock
  • only one thread can enter Write lock and no other thread can enter any lock

In practice though, almost all threading problems can be solved using read and write locks alone. To enter read/write lock, you need something like this:

private static readonly ReaderWriteLockSlim rwlock = new ReaderWriterLockSlim();
…
rwlock.EnterReadLock()
try
{
     // do something here
}
finally
{
     // don't forget to release the lock afterwards!
     rwlock.ExitReadLock();
}

As you can see, this can seriously clutter your code if you require read/write locks in many places! I saw this post on StackOverflow quite some time back and really like the pattern that Marc has presented:

http://stackoverflow.com/questions/170028/how-would-you-simplfy-entering-and-exiting-a-readerwriterlock

In his answer he showed how you can simplify the code needed to enter a read lock, here’s the full implementation you can use in your project:

public static class ReaderWriterLockSlimExtensions
{
     private sealed class ReadLockToken : IDisposable
     {
          private ReaderWriterLockSlim _sync;
          public ReadLockToken(ReaderWriterLockSlim sync)
          {
               _sync = sync;
               sync.EnterReadLock();
          }
          public void Dispose()
          {
               if (_sync != null)
               {
                    _sync.ExitReadLock();
                    _sync = null;
               }
          }
     }
     private sealed class WriteLockToken : IDisposable
     {
          private ReaderWriterLockSlim _sync;
          public WriteLockToken(ReaderWriterLockSlim sync)
          {
               _sync = sync;
               sync.EnterWriteLock();
          }
          public void Dispose()
          {
               if (_sync != null)
               {
                    _sync.ExitWriteLock();
                    _sync = null;
               }
          }
     }

     public static IDisposable Read(this ReaderWriterLockSlim obj)
     {
          return new ReadLockToken(obj);
     }
     public static IDisposable Write(this ReaderWriterLockSlim obj)
     {
          return new WriteLockToken(obj);
     }
}

And to use it in your code, this is all you’ll need:

using (_sync.Read())
{
     // do reading here
}
using (_sync.Write())
{
     // do writing here
}

Further Readings:

Jon Skeet’s tutorial on Multi-Threading in .Net

Ayande has a post on using the UpgradeableReadLock