У меня есть этот пример кода, и я пытаюсь выяснить, что происходит.
private static AutoResetEvent autoEvent = new AutoResetEvent(false);
private static Thread t1;
static void DoSomething()
{
Console.WriteLine("Main starting.");
ThreadPool.QueueUserWorkItem(
WorkMethod, autoEvent);
// Wait for work method to signal.
autoEvent.WaitOne();
// trying out does resource cleanup by using dispose and null where possible
autoEvent.SafeWaitHandle.Dispose();
t1 = null;
autoEvent = null;
autoEvent = new AutoResetEvent(false);
Console.WriteLine("Work method signaled.\nMain ending.");
}
static Action messageTarget;
static void WorkMethod(object stateInfo)
{
Console.WriteLine("Work starting.");
// This line is going to change
messageTarget = delegate()
{
Thread.Sleep(new Random().Next(100, 2000));
};
// Signal that work is finished.
Console.WriteLine("Work ending.");
((AutoResetEvent)stateInfo).Set();
}
Это прекрасно работает и создает 7 дескрипторов после цикла из 100 циклов (счетчик дескрипторов с использованием снимка памяти TestApi).
Теперь интересное поведение таково: когда я оборачиваюделегат в потоке
t1 = new Thread
(
delegate()
{
Thread.Sleep(new Random().Next(100, 2000));
});
t1.Start();
Приложение заканчивается примерно с 295 дескрипторами!
Я слышал, что .net framework плохо работает с потоками и очищает ресурсы, это правильно?Возможно, некоторые потоки все еще работают в фоновом режиме, когда приложение завершает, но уверены, что это немного экстремальное поведение?
Мой вопрос заключается в том, что вызывает такое большое количество ручек?(Обратите внимание, что это моделирует некоторое поведение в другом приложении и предназначено не для производства, а скорее для понимания, почему количество дескрипторов так резко увеличивается при использовании потоков)
Решение с Thread.Join
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Test.LeakDetection;
namespace FaultDetection
{
public partial class Form1 : Form
{
private Process process;
public Form1()
{
InitializeComponent();
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains("FaultDetection"))
{
//if the process is found to be running then we
//return a true
process = clsProcess;
}
}
MemorySnapshot s1;
if (process != null)
{
s1 = MemorySnapshot.FromProcess(process.Id);
for (int i = 0; i < 100; i++)
{
DoSomething();
MemorySnapshot s2 = MemorySnapshot.FromProcess(process.Id);
// Compare the two memory snapshots and generate a diff.
// Then display the diff to the console.
MemorySnapshot diff = s2.CompareTo(s1);
Console.WriteLine("\tHandle Count: {0}", diff.HandleCount);
label1.Text = "Handle Count: "+ diff.HandleCount + "\n";
}
}
}
private static AutoResetEvent autoEvent = new AutoResetEvent(false);
private static Thread t1;
private static List<Thread> threadReferences;
static void DoSomething()
{
Console.WriteLine("Main starting.");
ThreadPool.QueueUserWorkItem(
WorkMethod, autoEvent);
// Wait for work method to signal.
autoEvent.WaitOne();
t1.Join();
autoEvent.SafeWaitHandle.Dispose();
t1 = null;
autoEvent = null;
autoEvent = new AutoResetEvent(false);
Console.WriteLine("Work method signaled.\nMain ending.");
}
static Action messageTarget;
static void WorkMethod(object stateInfo)
{
Console.WriteLine("Work starting.");
t1 = new Thread
(
delegate()
{
Thread.Sleep(new Random().Next(100, 2000));
});
t1.Start();
//messageTarget = delegate() { Thread.Sleep(new Random().Next(100, 2000)); };
// Signal that work is finished.
Console.WriteLine("Work ending.");
((AutoResetEvent)stateInfo).Set();
}
}
}