2013-06-21 5 views
1

Я написал этот фрагмент кода:.NET многопоточные и исключение

 static void Main(string[] args) 
    { 
     Console.WriteLine("Start"); 

     Thread secondThread = new Thread(ThrowAnException); 
     secondThread.Start(); 

     Console.ReadKey(); 
    } 

    static void ThrowAnException() 
    { 
     throw new Exception("Second Thread Exception"); 
    } 
} 

Я понимаю, что, когда исключение происходит на втором потоке, исключение перемещается вниз стек потока, и если необработанные, ребенок нить заканчивается молча. Я вижу, что поток прерывает основной поток и ломается в методе ThrowAnException с «Исключение было необработанным».

Я запустил его как с отладкой, так и без него, и все будет одинаково.

Любые идеи, что я делаю неправильно?

+1

Возможный дубликат [Что происходит, когда .NET-поток генерирует исключение?] (Http://stackoverflow.com/questions/1668634/what-happens-when-a-net-thread-throws-an-exception) – Euphoric

+0

Как вы видите, что поток прерывает основной поток? – Timbo

+1

'детская нить завершается молча" - где вы столкнулись с этим? – YK1

ответ

7

Необработанные исключения завершают работу программы с .NET 2.0. Мысль о том, что основной поток получает «прерывание», не является правильным выбором ума, вся программа прерывается и все нити умирают. Это «грубая» версия Thread.Abort() и не может быть остановлена.

Произошел последний прорыв через событие AppDomain.UnhandledException. Он стреляет, чтобы дать вам возможность зарегистрировать значение e.UnhandledException.ToString(), чтобы у вас был шанс диагностировать сбой. Часто упускают из виду, но крайне важно справляться с авариями, когда ваша программа выходит в дикой природе, а пользователи и их машины часто обрабатывают вашу программу удивительные способы, которые вы не задумывались.

На самом деле невозможно не свернуть программу с атрибутом в файле .config, который переопределяет политику CLR по умолчанию. Но в этом заключается безумие, потоки, которые заканчиваются, не заканчивая свою работу, просто заставляют программы ошибочно вести себя совершенно неудовлетворительно. Пробовал в .NET 1.x и отклонялся как плохая идея.

0

Ваше понимание почти правильно.

Любое необработанное исключение (кроме ThreadAbortException) в потоке идет вниз по стеклу вызова, эффективно разбивая его. то нить молча убита. но катастрофа здесь не останавливается. исключение затем продолжает потреблять весь текущий процесс. но как раз перед тем, как процесс будет убит, будет возбуждено событие AppDomain.UnhandledException. это дает вам возможность регистрировать исключение (или выложить большое сообщение об ошибке). isTerminating Недвижимость UnhanledExceptionEventArgs всегда true.

Следует отметить, что в dot-net среди потоков нет отношений между родителем и ребенком. все потоки равны. Единственное, что ниже нить - это сам AppDomain.

Теперь, чтобы объяснить, что вы видели, исключение во втором потоке (не дочерняя нить) не прерывало или вообще не влияло на первую нить. вторая нить убита. то весь процесс убит. как только процесс будет убит, первому потоку некуда будет скрыться. он обречен на смерть. теперь, если код работает в visual studio (прикреплен отладчик), отладчик может поймать исключение, как только он понял, что нет никакого блока catch, чтобы его поймать. то есть если вы видите это взлом основная нить. отладчик не просто ломается в основном потоке, он приостанавливает ВСЕ потоки, в том числе тот, в котором произошло исключение. это дает вам возможность изменить код и возобновить его.

без отладчика, исключение ест собственную нить, затем оно потребляет весь процесс.

+0

В действительности есть намного меньше еды и потребления. Когда CLR обнаруживает необработанное исключение, он отключается. Ничего разрушительного не происходит с потоками/процессами, как вы предлагаете. –

+0

Спасибо всем ответам - если я могу отметить все 3 правильно, я это сделаю. –

0

То, что вы видите, является правильным поведением. Необработанное исключение в любом потоке, запущенном пользователем, приведет к сбою программы.

the child thread terminates silently

Может быть, просто, может быть, то, что вы описали это с древних времен .NET 1.x. Это больше не относится к .NET 2.0 и более поздним версиям.

Все сказано, что есть способы, с помощью которых потоки могут не запускать программу. (Это просто для демонстрации, а не для практики. Никогда этого не делайте).

Action a = ThrowAnException; 
    a.BeginInvoke(null, null); 

Это заставит ThrowAnException называться на ThreadPool нить с помощью APM. Вы никогда не увидите исключение, пока не позвоните EndInvoke. Тем не менее, APM больше не рекомендуется использовать асинхронность.

Посмотрите на параллельную библиотеку задач C# 4.0 и C# 5.0 async/ожидайте некоторую удивительность .NET/C#.