Multi-threaded code is challenging to get right and even harder to debug once it’s gone wrong. This is especially true when attempting to collect data from multiple threads. To make this easier, many .NET collection classes include the SyncRoot property to maintain proper synchronization with other threads that might be simultaneously modifying the collection. But then Microsoft changed its mind in .NET 2.0 and decided to let the developer decide how to manage synchronization, and so none of the new generic collections have a SyncRoot property.

What is SyncRoot?

SyncRoot is an internal object a class uses to allow multiple threads to access and share its data. Some classes expose the SyncRoot object so that client code can also gain exclusive access for operations that need to be atomic. For example, to lock an ArrayList, you would use the lock statement on the ArrayList’s SyncRoot property:

ArrayList list = new ArrayList();
lock (list.SyncRoot)
{
    list.Add( "test" );
}

Why Not lock(this)

Some programmers might be tempted to lock the entire array, such as:

ArrayList l = new ArrayList();
lock (l)
{
    l.Add( "test" );
}

However, this makes it very difficult to debug synchronization issues. Whereas if all clients have to lock an object through its SyncRoot property, you can set a breakpoint in the property and see who is trying to lock the object and whether another thread already has a lock.

Create Your Own SyncRoot

You can use any object as your SyncRoot, as long as you use the same one for all clients. Following is a simple example of a class that provides its own SyncRoot:

public class MyIntegerList
{
    private readonly object m_SyncRoot = new object();
    private readonly List<int> m_List = new List<int>();
    public object SyncRoot
    {
        get
        {
            return this.m_SyncRoot;
        }
    }
}

So then clients would lock its SyncRoot:

MyIntegerList list = new MyIntegerList();
lock( list.SyncRoot )
{
    list.Add( 42 );
}