Кажется, что блок finally не выполняется, если он выполняет код, отличный от основного потока. Можно ли принудительно выполнить в этом случае?
Среда: VS 2010, .Net Framework 4.0.3
class Program
{
static void Main(string[] args)
{
var h = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(
obj => TestProc(h));
h.WaitOne();
}
private static void TestProc(EventWaitHandle h)
{
try
{
Trace.WriteLine("Try");
h.Set();
}
catch(Exception)
{
Trace.WriteLine("Catch");
}
finally
{
Thread.Sleep(2000);
Trace.WriteLine("Finally");
}
}
}
Обновление:
Я нашел упоминания и объяснения по этому поводу в MSDN:
Класс ThreadAbortException http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx
Когда вызывается метод Abort для уничтожения потока, среда CLR генерирует исключение ThreadAbortException. ThreadAbortException - это специальное исключение, которое может быть перехвачено, но оно будет автоматически вызвано снова в конце блока перехвата. Когда возникает это исключение, среда выполнения выполняет все блоки finally перед завершением потока. Поскольку поток может выполнять неограниченные вычисления в блоках finally или вызывать Thread.ResetAbort для отмены прерывания, нет никакой гарантии, что поток когда-либо завершится. Если вы хотите дождаться завершения прерванного потока, вы можете вызвать метод Thread.Join. Присоединение - это блокирующий вызов, который не возвращается, пока поток не прекратит выполнение.
Примечание:
Когда среда CLR останавливает фоновые потоки после завершения всех потоков переднего плана в управляемом исполняемом файле, Thread.Abort не используется. Следовательно, вы не можете использовать ThreadAbortException, чтобы определить, когда фоновые потоки завершаются CLR.
Передний план и фоновые потоки http://msdn.microsoft.com/en-us/library/h339syd0.aspx
Когда среда выполнения останавливает фоновый поток, потому что процесс завершается, в потоке не возникает никаких исключений. Однако, когда потоки останавливаются из-за того, что метод AppDomain.Unload выгружает домен приложения, возникает исключение ThreadAbortException как в потоках переднего плана, так и в фоновых потоках.
Так почему же в конце приложения CLR не использует метод AppDomain.Unload для выгрузки домена приложения перед завершением (уничтожением) основного процесса? Поскольку http://msdn.microsoft.com/en-us/library/system.appdomain.unload.aspx:
Когда поток вызывает Unload, целевой домен помечается для выгрузки. Выделенный поток пытается выгрузить домен, и все потоки в домене прерываются. Если поток не прерывается, например, потому что он выполняет неуправляемый код или потому что он выполняет блок finally, то по прошествии определенного периода времени в потоке, который изначально вызывал Unload, создается исключение CannotUnloadAppDomainException. Если поток, который не удалось прервать, в конечном итоге завершается, целевой домен не выгружается. Таким образом, в домене .NET Framework версии 2.0 не гарантируется выгрузка, поскольку может быть невозможно завершить выполнение потоков.
Заключение: в некоторых случаях мне нужно подумать, будет ли мой код выполняться в фоновом или переднем потоке? Возможно ли, что мой код не будет завершен до того, как основной поток приложения завершит всю работу?