Jedna z moich metod ( Method1) tworzy nowy wątek. Ten wątek wykonuje metodę ( Method2) i podczas egzekwowania generowany jest wyjątek. Potrzebuję informacji o wyjątku w metodzie wywołującej ( Method1)
Czy jest jakiś sposób, w jaki mogę złapać ten wyjątek, Method1który jest wrzucany Method2?
W .NET 4 i nowszych możesz użyć Task<T>class zamiast tworzyć nowy wątek. Następnie możesz uzyskać wyjątki za pomocą .Exceptionswłaściwości obiektu zadania. Można to zrobić na dwa sposoby:
W osobnej metodzie: // przetwarzasz wyjątek w wątku jakiegoś zadania
Przepraszam, ale zapomniałem wspomnieć, że używam .NET 3.5. Jak rozumiem, zadanie to 4.0?
Silverlight Student
2
@SilverlightStudent Ok, właśnie zaktualizowałem moją odpowiedź, aby spełnić Twoje wymagania.
oxilumin
@oxilumin: Dziękuję i bardzo doceniam. Jeszcze jedno pytanie uzupełniające. Jeśli Twoja metoda Test () również przyjmuje kilka argumentów, to w jaki sposób zmodyfikujesz metodę SafeExecute dla tych argumentów?
Silverlight Student
2
@SilverlightStudent W tym przypadku podam zamiast niego lambdę Test. Podobnie jak() => Test(myParameter1, myParameter2)
oxilumin
2
@SilverlightStudent: Zaktualizowano.
oxilumin
9
Nie możesz złapać wyjątku w Method1. Możesz jednak złapać wyjątek w Method2 i zapisać go w zmiennej, którą oryginalny wątek wykonania może następnie odczytać i pracować z nim.
Dzięki za twoją odpowiedź. Więc jeśli Method1 jest częścią Class1 i mam zmienną typu Exception w tej klasie. Za każdym razem, gdy Method2 zgłasza wyjątek, ustawia również tę zmienną wyjątku w Class1. Czy to brzmi jak uczciwy projekt? Czy istnieją najlepsze sposoby postępowania w tym scenariuszu?
Silverlight Student
Prawidłowo, po prostu zapisujesz wyjątek i uzyskujesz do niego dostęp później. Często zdarza się, że metody uruchomione w przyszłości (zwłaszcza wywołania zwrotne, gdy Metoda 2 jest kompletna), ponownie generują wyjątek tak, jakby to one same spowodowały, ale to naprawdę zależy od tego, czego chcesz.
ermau
0
Najprostsza metoda udostępniania danych między różnymi wątkami jest shared datanastępująca (niektóre to pseudokod):
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 tej metodzie możesz przeczytać w tym miłym wprowadzeniu o wielowątkowości , jednak ja wolałem przeczytać o tym w O'Reilly book C# 3.0 in a nutshellopracowaniu braci Albahari (2007), które jest również dostępne bezpłatnie w Google Books, podobnie jak nowsza wersja książki, ponieważ obejmuje również łączenie wątków, wątki pierwszego planu i wątki w tle itp., Z ładnym i prostym przykładowym kodem. (Zastrzeżenie: mam zniszczoną kopię tej książki)
Jeśli tworzysz aplikację WinForms, korzystanie z udostępnionych danych jest szczególnie przydatne, ponieważ kontrolki WinForm nie są bezpieczne wątkowo. Używając wywołania zwrotnego do przekazywania danych z wątku roboczego z powrotem do kontrolki WinForm, główny wątek interfejsu użytkownika wymaga brzydkiego kodu, Invoke()aby zapewnić bezpieczeństwo wątku kontrolnego. Zamiast tego, korzystając z udostępnionych danych i jednowątkowego System.Windows.Forms.Timer, w krótkim czasie, Intervalpowiedzmy 0,2 sekundy, możesz łatwo wysyłać informacje z wątku roboczego do kontrolki bez Invoke.
Miałem szczególny problem polegający na tym, że chciałem użyć elementów zawierających kontrolki z zestawu testów integracji, więc musiałem utworzyć wątek STA. Kod, który otrzymałem, jest następujący, wstaw go tutaj na wypadek, gdyby inni mieli ten sam problem.
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){...}
To jest bezpośrednie wklejenie kodu w obecnej postaci. W przypadku innych zastosowań zalecałbym podanie akcji lub funkcji jako parametru i wywołanie jej w wątku zamiast kodowania wywoływanej metody na stałe.
Test
. Podobnie jak() => Test(myParameter1, myParameter2)
Nie możesz złapać wyjątku w Method1. Możesz jednak złapać wyjątek w Method2 i zapisać go w zmiennej, którą oryginalny wątek wykonania może następnie odczytać i pracować z nim.
źródło
Najprostsza metoda udostępniania danych między różnymi wątkami jest
shared data
następująca (niektóre to pseudokod):O tej metodzie możesz przeczytać w tym miłym wprowadzeniu o wielowątkowości , jednak ja wolałem przeczytać o tym w
O'Reilly book C# 3.0 in a nutshell
opracowaniu braci Albahari (2007), które jest również dostępne bezpłatnie w Google Books, podobnie jak nowsza wersja książki, ponieważ obejmuje również łączenie wątków, wątki pierwszego planu i wątki w tle itp., Z ładnym i prostym przykładowym kodem. (Zastrzeżenie: mam zniszczoną kopię tej książki)Jeśli tworzysz aplikację WinForms, korzystanie z udostępnionych danych jest szczególnie przydatne, ponieważ kontrolki WinForm nie są bezpieczne wątkowo. Używając wywołania zwrotnego do przekazywania danych z wątku roboczego z powrotem do kontrolki WinForm, główny wątek interfejsu użytkownika wymaga brzydkiego kodu,
Invoke()
aby zapewnić bezpieczeństwo wątku kontrolnego. Zamiast tego, korzystając z udostępnionych danych i jednowątkowegoSystem.Windows.Forms.Timer
, w krótkim czasie,Interval
powiedzmy 0,2 sekundy, możesz łatwo wysyłać informacje z wątku roboczego do kontrolki bezInvoke
.źródło
Miałem szczególny problem polegający na tym, że chciałem użyć elementów zawierających kontrolki z zestawu testów integracji, więc musiałem utworzyć wątek STA. Kod, który otrzymałem, jest następujący, wstaw go tutaj na wypadek, gdyby inni mieli ten sam problem.
To jest bezpośrednie wklejenie kodu w obecnej postaci. W przypadku innych zastosowań zalecałbym podanie akcji lub funkcji jako parametru i wywołanie jej w wątku zamiast kodowania wywoływanej metody na stałe.
źródło