Try/Catch and threading
У меня есть идея, почему, но я хотел бы спросить, есть ли у кого-то хорошее понимание того, почему исключение, возникшее внутри потока, никогда не попадает в код, который его начал. Вот какой очень простой код, чтобы продемонстрировать, что я имею в виду:
using System;
using System.Collections.Generic;
using System.Threading;
namespace TestCrash
{
class Program
{
private static void Crash(object control)
{
AutoResetEvent are = (AutoResetEvent)(((object[])control)[0]);
are.Set();
throw new Exception("Burn baby burn");
}
static void Main(string[] args)
{
try
{
List<WaitHandle> waitHandles = new List<WaitHandle>();
for (int i = 0; i < 100; i++)
{
AutoResetEvent are = new AutoResetEvent(false);
waitHandles.Add(are);
object[] procControl = new object[] { are };
ThreadPool.QueueUserWorkItem(Crash, procControl);
WaitHandle.WaitAll(waitHandles.ToArray());
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
Я наивно полагал, что, пытаясь попробовать/поймать, я был бы в безопасности, но я обнаружил, что это не так (он разбивает одну из моих служб).
Ответы
Ответ 1
Ну, в общем, вы не знаете, где будет происходить поток, который будет происходить к тому времени, когда исключение будет добавлено в новый поток - почему он будет ждать, пока поток выкинет исключение?
Подумайте о задействованных стеках - когда генерируется исключение, оно поднимается до стека, пока не достигнет соответствующего блока catch. Новый поток имеет полностью отдельный стек для создающего потока, поэтому он никогда не достигнет блока catch в стеке создания потоков.
EDIT: Конечно, вы могли бы создать свою систему так, чтобы создающий поток ожидал, что произойдут другие вещи - немного похоже на цикл сообщений в приложении Windows Forms. Новый поток может затем поймать исключение и отправить сообщение в создающий поток, который затем может обрабатывать исключение. Это не нормальная настройка, хотя вы должны делать все это явно.
Ответ 2
Неплохая идея делать предположения, особенно когда задействованы несколько потоков (вы знаете это старое высказывание).
Почему код, который запустил поток, видит исключение? Код, который начал поток, может даже не существовать, когда генерируется исключение.
Ответ 3
Прогонный поток не попадает в ваш оператор try/catch, потому что он работает в другом потоке. Try/Catch работает только для текущего потока. Что вам нужно сделать, это попробовать/поймать функцию, выполняемую потоком, и иметь способ управления тем, что происходит, когда происходит этот сбой.
Ответ 4
Возможно, вы захотите использовать EventGeneratingThread wrapper - это позволит вам поймать и обработать исключения, созданные в потоках процесса, породившего их.
Ответ 5
Попробуйте добавить это перед своим DoWork Sub
<System.Diagnostics.DebuggerNonUserCodeAttribute()> _
Я использую фона рабочего, и все Try Catch в моем цикле работают так же, как вы ожидали бы от них.