Задачи 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;
}
}