I recently read this article Safe Thread Synchronization as I was curious about the thread safety of calls made from a finaliser. I wrote the following code to test access to a static thread safe collection from a finaliser.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GCThreadTest
{
class Program
{
static class FinaliserCollection
{
private static Queue<int> s_ItemQueue = new Queue<int>();
private static System.Object s_Lock = new System.Object();
public static void AddItem(int itemValue)
{
lock(s_Lock)
{
s_ItemQueue.Enqueue(itemValue);
}
}
public static bool TryGetItem(out int item)
{
lock(s_Lock)
{
if (s_ItemQueue.Count <= 0)
{
item = -1;
return false;
}
item = s_ItemQueue.Dequeue();
return true;
}
}
}
class FinaliserObject
{
private int m_ItemValue;
public FinaliserObject(int itemValue)
{
m_ItemValue = itemValue;
}
~FinaliserObject()
{
FinaliserCollection.AddItem(m_ItemValue);
}
}
static void Main(string[] args)
{
int itemValueIn = 0;
int itemValueOut = 0;
while (itemValueOut < 10000)
{
System.Threading.ThreadPool.QueueUserWorkItem
(delegate(object value)
{
new FinaliserObject((int)value);
System.Threading.Thread.Sleep(5);
}, itemValueIn);
itemValueIn = itemValueIn + 1;
// This seems to stop finaliser from
// being called?
// System.Threading.Thread.Sleep(5);
int tempItemValueOut = -1;
if (FinaliserCollection.TryGetItem(out tempItemValueOut))
itemValueOut = tempItemValueOut;
}
System.Console.WriteLine("Finished after {0} items created", itemValueOut);
System.Console.ReadLine();
}
}
}
Without the 'Sleep' call in the while loop this code seems to run fine but is it really safe from deadlocking? Would it ever be possible for a finaliser call to be made while a queued thread pool item is accessing the static collection? Why does adding the 'Sleep' to the main threads while loop appear to stop all finalisers from being called?