J'ai récemment lu cet article Synchronisation sécurisée des threads car je m'intéressais à la sûreté des threads des appels effectués à partir d'un finaliseur. J'ai écrit le code suivant pour tester l'accès à une collection statique thread-safe à partir d'un finaliseur.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GCThreadTest
{
class Program
{
static class FinaliserCollection
{
private static Queue s_ItemQueue = new Queue();
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();
}
}
}
Sans l'appel 'Sleep' dans la boucle while, ce code semble fonctionner correctement, mais est-il vraiment à l'abri du deadlocking? Serait-il jamais possible qu'un appel à un finaliseur soit effectué pendant qu'un élément de la file d'attente du pool de threads y accède? Pourquoi ajouter 'Sleep' à la boucle while du thread principal semble arrêter l'appel de tous les finaliseurs?