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]
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;
}
}