Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Threading & Blocking [closed]

I am wondering which one is better approach to load data in a thread safe fashion. Traditionally, I have used the double lock pattern and that served the purpose quite well. Now, with the addition of System.Lazy type, I am wondering if relying on the internals of Lazy and Loading is better and do the job in a much better way. It does look cleaner and easier to read but is it better?

Any thoughts?

namespace SomeNameSpace
{
  public class DataStoreContext
  {
    private readonly static Lazy<DataStoreContext> context = new Lazy<DataStoreContext>(() => new DataStoreContext());
    private Lazy<Dictionary<string, Entity>> _entities = new Lazy<Dictionary<string, Entity>>(() => { return DataStoreContext.Instance.Load(); });
    private readonly object _syncRoot = new object();
    private DataStoreContext()
    {
    }

    public Dictionary<string, Entity> Data
    {
      get { return _entities.Value; }
    }

    public static DataStoreContext Instance
    {
      get { return context.Value; }
    }

    private Dictionary<string, Entity> Load()
    {
      // Load Data from some data store. 
      return null;
    }

    private Dictionary<string, Entity> LoadWithLock()
    {
      if (_entities == null)
      {
        lock (_syncRoot)
        {
          if (_entities == null)
          {
            Dictionary<string, Entity> entities = this.Load();
            _entities = entities;
            return _entities;
          }
        }
      }

      return _entities ;
    }

    public void Clear()
    {

     _entities = new Lazy<Dictionary<string, Entity>>(() => { return DataStoreContext.Instance.Load(); });

    }
  }
}
like image 602
Sam Avatar asked Oct 10 '12 01:10

Sam


2 Answers

It does look cleaner and easier to read but is it better?

Yes. Double-checked locking is difficult to get right. It requires a memory barrier to be correct. Your implementation isn't actually guaranteed safe by the CIL*.

For details, see this Wikipedia entry.

By using Lazy<T>, you get code that is not only cleaner, but is actually correct on all platforms.

*Note that this likely works perfectly on x86 and x64, running the Microsoft runtime, due to the memory model of the platform. However, it's not guaranteed by spec to be correct without proper memory barriers.

like image 185
Reed Copsey Avatar answered Oct 22 '22 09:10

Reed Copsey


Per MSDN's documentation:

By default, all public and protected members of the Lazy class are thread safe and may be used concurrently from multiple threads. These thread-safety guarantees may be removed optionally and per instance, using parameters to the type's constructors.

It is quite thread safe for both read and write operations. Therefore, I would say stick with this because it's much cleaner.

But, just as the documentation states, you can turn off that thread safety with some optional parameters to the constructor.

like image 3
Mike Perrenoud Avatar answered Oct 22 '22 09:10

Mike Perrenoud