Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some clarification on the SyncRoot pattern: what is the correct way to use this pattern?

I read something about the SyncRoot pattern as a general rule to avoid deadlocks. And reading a question of a few years ago (see this link), I think I understand that some uses of this pattern may be incorrect. In particular, I focused on the following sentences from this topic:

You’ll notice a SyncRoot property on many of the Collections in System.Collections. In retrospeced, I think this property was a mistake... Rest assured we will not make the same mistake as we build the generic versions of these collections.

In fact, for example, List<T> class doesn't implements SyncRoot property, or more correctly it is implemented explicitly (see this answer), so you must cast to ICollection in order to use it. But this comment argues that making a private SyncRoot field public is as bad practice as locking on this (see this answer), as also confirmed in this comment.

So, if I understand correctly, when I implement a non thread-safe data structure, since it could be used in a multithreaded context, I should not (actually, I must not) provide the SyncRoot property. But I should leave the developer (who will use this data structure) with the task of associating it with a private SyncRoot object as in the following sample code.

public class A
{
    private MyNonThreadSafeDataStructure list;
    private readonly object list_SyncRoot = new object;

    public Method1()
    {
        lock(list_SyncRoot)
        {
            // access to "list" private field
        }
    }

    public Method2()
    {
        lock(list_SyncRoot)
        {
            // access to "list" private field
        }
    }
}

In summary, I understood that the best practices for synchronization/locking should be as follows:

  1. Any private SyncRoot objects should not be exposed through a public property; in other words, a custom data structure should not provide a public SyncRoot property (see also this comment).
  2. In general, it is not mandatory to use private objects for locking (see this answer).
  3. If a class has multiple sets of operations that need to be synchronised, but not with each other, it should have multiple private SyncRoot objects (see this comment).

Is what written above the proper use of this pattern?

like image 713
enzom83 Avatar asked Sep 14 '12 12:09

enzom83


1 Answers

I would avoid adding a SyncRoot property to the type that I design, here are the reasons:

  • Users of my type may need to use different synchronisation mechanism, for example Mutex, or ReaderWriterLock or ReaderWriterLockSlim etc

  • The type becomes fatter: its responsibility becomes more scattered. Why would I add support for explicit multithreading locking and no support for other fluff? I would force the user to follow only one practise, which may not be the best solution in all cases

  • I would need to implement the property correctly (no returning this or typeof(MyClass)), i.e. this is wrong:

    public object SyncRoot {get {return this;}}
    

I would also avoid using SyncRoot property from the .NET framework types. If I need to make a type w/o SyncRoot property threadsafe I will use one locking pattern, and if a type has this property I will still not opt for locking on SyncRoot. This makes my code style consistent and easier to read/maintain.

like image 108
oleksii Avatar answered Nov 09 '22 04:11

oleksii