Search code examples
c#synchronizationtask-parallel-libraryreaderwriterlockslim

TPL Tasks and ReaderWriterLockSlim


I've got a strange bug in my current project. Thats why I have two questions:

1) Why does this occur?
2) How do I solve this?

Some additional info: I'm running this on a System with a QuadCore CPU (Intel Core2Quad Q9650)

I have a Function "DoSomething()" that could be called from multiple Threads at a time:

public class SingletonClass    
{

    // Singleton
    public static SingletonClass Instance 
    {
        get { return _instance ?? (_instance = new SingletonClass()); }
    }

    private readonly ReaderWriterLockSlim _workLock = new ReaderWriterLockSlim();
    private bool _isWorkDone = false;

    // bool returns true for "Inner Task executed" and false for "Inner Task had been executed earlier"
    public bool DoSomething()
    {
        // workaround to fix: Thread.Sleep(50);
        _workLock.EnterWriteLock();
        try
        {
            if (!_isWorkDone)
            {
                Task.Factory.StartNew(DoWork());
                _isWorkDone = true;
                return true;
            }

            return false;
        }
        finally
        {
           _workLock.ExitWriteLock();
        }
    }
}

In order to test if this function works I used the TPL to create multiple Tasks calling this function nearly simultaniously:

for (int i = 0; i < 10; i += 1)
{
    Task.Factory.StartNew(() =>
    {
        bool success = DoSomething();
        Console.WriteLine(success);
    });
}

I expected to get an output like this:

true, false, false, ....

But what I got was this:

true, true, true, true, false, false ....

Remember:
1) Why?
2) How to solve?

EDIT: I added a sample-project: [DELETED - Problem solved]


Solution

  • No way, the problem is not in the lock but in the creation of the Singleton!

    public static Dll Instance
    {
        get { return _INSTANCE ?? (_INSTANCE = new Dll()); }
    }
    

    The above is not protected by the lock => you get 4 different instances! Four Different locks!

    private void CreateThreadsToAccess()
    {
        Task[] tasks = new Task[10];
        for (int i = 0; i < tasks.Length; i += 1)
        {
            tasks[i] = Task.Factory.StartNew(() =>
            {
            //  here you get four different instances
                bool success = Dll.Instance.DoSomething();
                Console.WriteLine(success);
            });
        }
    
        Task.WaitAll(tasks);
    
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
    

    How to correct:

    private static readonly object mylock = new object();
    public static Dll Instance
    {
        get 
        {
           if (_INSTANCE == null) 
           {
               lock (mylock) 
               {
                  if (_INSTANCE == null) 
                  {
                     _INSTANCE = new Dll();
                  }
               }
           }
           return _INSTANCE;
        }
    }