Задачи TPL и ReaderWriterLockSlim

У меня странная ошибка в моем текущем проекте. Вот почему у меня есть два вопроса:

1) Почему это происходит?
2) Как мне это решить?

Некоторая дополнительная информация: я запускаю это в системе с процессором QuadCore (Intel Core2Quad Q9650)

У меня есть функция "DoSomething()", которая может быть вызвана из нескольких потоков одновременно:

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();
        }
    }
}

Чтобы проверить, работает ли эта функция, я использовал TPL для создания нескольких Задач, вызывающих эту функцию почти одновременно:

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

Я ожидал получить вывод, как это:

правда, ложь, ложь,....

Но то, что я получил, было так:

правда, правда, правда, правда, ложь, ложь....

Помните:
1) почему?
2) Как решить?

РЕДАКТИРОВАТЬ: Я добавил образец проекта: [УДАЛЕНО - Проблема решена]

1 ответ

Решение

Нет, проблема не в замке, а в создании Singleton!

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

Вышеуказанное не защищено замком => вы получаете 4 разных экземпляра! Четыре разных замка!

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();
}

Как исправить:

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;
    }
}
Другие вопросы по тегам