Les threads comptent comme des objets racine; Je ne sais pas exactement comment BackgroundWorker fonctionne, mais il semble probable que la méthode de thread primaire va accéder à l'état sur l'instance de travail; en tant que tel, le thread de travail gardera en vie l'instance de BackgroundWorker jusqu'à ce que (au moins) le thread se soit arrêté.
Bien sûr; la collection exige également que tous les autres objets (vivants) aient dé-référencé l'objet de travail; notez également que la collection de variables de pile peut être différente dans le débogage/la libération et avec/sans un débogueur attaché.
[edit] Comme cela a également été noté; les gestionnaires d'événements sur le worker (dans votre code) garderont les objets "view" et "update" en vie (via le délégué), mais pas l'inverse. Tant que le travailleur a une durée de vie plus courte que la «vue» et la «mise à jour», vous n'avez pas besoin d'être paranoïaque à propos de la désinscription des événements. J'ai modifié le code pour inclure un objet "SomeTarget" qui n'est référencé que par le worker: vous devriez voir cet effet (c'est-à-dire que la cible meurt avec le worker).
Re travailleur récupéré lorsque le fil meurt: voici la preuve; vous devriez voir « travailleur finalisé » après que le travailleur signale la sortie:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Demo : Form
{
class ChattyWorker : BackgroundWorker
{
~ChattyWorker()
{
Console.WriteLine("Worker finalized");
}
}
class SomeTarget
{
~SomeTarget()
{
Console.WriteLine("Target finalized");
}
public SomeTarget()
{
Console.WriteLine("Target created");
}
public void Foo(object sender, EventArgs args)
{
Console.WriteLine("Foo");
}
}
static void Collect(object sender, EventArgs args)
{
Console.WriteLine("Collecting...");
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Tick += Collect;
timer.Start();
ChattyWorker worker = new ChattyWorker();
worker.RunWorkerCompleted += new SomeTarget().Foo;
worker.DoWork += delegate
{
Console.WriteLine("Worker starting");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(250);
Console.WriteLine(i);
}
Console.WriteLine("Worker exiting");
};
worker.RunWorkerAsync();
}
[STAThread]
static void Main()
{ // using a form to force a sync context
Application.Run(new Demo());
}
}
Comment savez-vous qu'ils ne sont pas collectés? – StingyJack