исключение catch, которое создается в другом потоке
110
Один из моих методов ( Method1) порождает новый поток. Этот поток выполняет метод ( Method2), и во время выполнения возникает исключение. Мне нужно получить эту информацию об исключении в вызывающем методе ( Method1)
Есть ли каким - то образом я могу поймать это исключение в Method1том , что брошен в Method2?
В .NET 4 и выше вы можете использовать Task<T>класс вместо создания нового потока. Затем вы можете получить исключения, используя .Exceptionsсвойство объекта задачи. Сделать это можно двумя способами:
Отдельным методом: // Вы обрабатываете исключение в каком- то потоке задачи
Извините, но я забыл упомянуть, что использую .NET 3.5. Насколько я понимаю, задача 4.0?
Студент Silverlight,
2
@SilverlightStudent Хорошо, я только что обновил свой ответ, чтобы удовлетворить ваши требования.
оксилумин
@oxilumin: Спасибо и очень признателен. Еще один уточняющий вопрос. Если ваш метод Test () также принимает несколько аргументов, как вы измените метод SafeExecute для этих аргументов?
Студент Silverlight
2
@SilverlightStudent В этом случае я передам лямбду вместо Test. Like() => Test(myParameter1, myParameter2)
оксилумин
2
@SilverlightStudent: Обновлено.
оксилумин
9
Вы не можете поймать исключение в Method1. Однако вы можете перехватить исключение в Method2 и записать его в переменную, которую исходный поток выполнения может затем прочитать и с которой будет работать.
Спасибо за ваш ответ. Итак, если Method1 является частью Class1, и у меня есть переменная типа Exception в этом классе. Всякий раз, когда Method2 выдает исключение, он также устанавливает эту переменную исключения в Class1. Звучит как честный дизайн? Есть ли какие-либо передовые способы решения этого сценария?
Студент Silverlight
Правильно, вы просто сохраняете исключение и получаете к нему доступ позже. Нередко методы, запускаемые в будущем (особенно обратные вызовы, когда метод Method2 завершен), затем повторно генерируют это исключение, как если бы они сами его вызвали, но это действительно зависит от того, что вы хотите.
ermau
0
Самый простой способ обмена данными между разными потоками выглядит shared dataследующим образом (некоторые из них являются псевдокодом):
classMyThread{publicstringSharedData;publicvoidWorker(){...lengthy action, infinite loop, etc...SharedData="whatever";...lengthy action...return;}}classProgram{staticvoidMain(){MyThread m =newMyThread();ThreadWorkerThread=newThread(m.Worker);WorkerThread.Start();
loop//or e.g. a Timer thread{
f(m.SharedData);}return;}}
Вы можете прочитать об этом методе в этом красивом введении о многопоточности , однако я предпочел прочитать об этом в O'Reilly book C# 3.0 in a nutshellкниге братьев Альбахари (2007), которая также находится в свободном доступе в Google Книгах, как и более новая версия книги. потому что он также охватывает пул потоков, потоки переднего плана по сравнению с фоновыми потоками и т. д. с красивым и простым примером кода. (Отказ от ответственности: у меня есть изношенная копия этой книги)
Если вы создаете приложение WinForms, использование общих данных особенно удобно, поскольку элементы управления WinForm не являются потокобезопасными. Используя обратный вызов для передачи данных из рабочего потока обратно в элемент управления WinForm, основной поток пользовательского интерфейса нуждается в уродливом коде, Invoke()чтобы сделать этот элемент управления потокобезопасным. Используя вместо этого общие данные и однопоточные System.Windows.Forms.Timer, с коротким, Intervalскажем, 0,2 секунды, вы можете легко отправлять информацию из рабочего потока в элемент управления без Invoke.
У меня была особая проблема в том, что я хотел использовать элементы, содержащие элементы управления, из набора интеграционных тестов, поэтому мне пришлось создать поток STA. Код, который у меня получился, выглядит следующим образом, на случай, если у других возникнет такая же проблема.
publicBoolean?Dance(String name){// Already on an STA thread, so just go for itif(Thread.CurrentThread.GetApartmentState()==ApartmentState.STA)returnDanceSTA(name);// Local variable to hold the caught exception until the caller can rethrowException lException =null;Boolean? lResult =null;// A gate to hold the calling thread until the called thread is donevar lGate =newManualResetEvent(false);var lThreadStart =newThreadStart(()=>{try{
lResult =DanceSTA(name);}catch(Exception ex){
lException = ex;}
lGate.Set();});var lThread =newThread(lThreadStart);
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
lGate.WaitOne();if(lException !=null)throw lException;return lResult;}publicBoolean?DanceSTA(String name){...}
Это прямая вставка кода как есть. Для других целей я бы рекомендовал предоставить действие или функцию в качестве параметра и вызывать их в потоке вместо жесткого кодирования вызываемого метода.
Test
. Like() => Test(myParameter1, myParameter2)
Вы не можете поймать исключение в Method1. Однако вы можете перехватить исключение в Method2 и записать его в переменную, которую исходный поток выполнения может затем прочитать и с которой будет работать.
источник
Самый простой способ обмена данными между разными потоками выглядит
shared data
следующим образом (некоторые из них являются псевдокодом):Вы можете прочитать об этом методе в этом красивом введении о многопоточности , однако я предпочел прочитать об этом в
O'Reilly book C# 3.0 in a nutshell
книге братьев Альбахари (2007), которая также находится в свободном доступе в Google Книгах, как и более новая версия книги. потому что он также охватывает пул потоков, потоки переднего плана по сравнению с фоновыми потоками и т. д. с красивым и простым примером кода. (Отказ от ответственности: у меня есть изношенная копия этой книги)Если вы создаете приложение WinForms, использование общих данных особенно удобно, поскольку элементы управления WinForm не являются потокобезопасными. Используя обратный вызов для передачи данных из рабочего потока обратно в элемент управления WinForm, основной поток пользовательского интерфейса нуждается в уродливом коде,
Invoke()
чтобы сделать этот элемент управления потокобезопасным. Используя вместо этого общие данные и однопоточныеSystem.Windows.Forms.Timer
, с коротким,Interval
скажем, 0,2 секунды, вы можете легко отправлять информацию из рабочего потока в элемент управления безInvoke
.источник
У меня была особая проблема в том, что я хотел использовать элементы, содержащие элементы управления, из набора интеграционных тестов, поэтому мне пришлось создать поток STA. Код, который у меня получился, выглядит следующим образом, на случай, если у других возникнет такая же проблема.
Это прямая вставка кода как есть. Для других целей я бы рекомендовал предоставить действие или функцию в качестве параметра и вызывать их в потоке вместо жесткого кодирования вызываемого метода.
источник