catch exception qui est levée dans un thread différent
110
Une de mes méthodes ( Method1) génère un nouveau thread. Ce thread exécute une méthode ( Method2) et pendant l'exécution, une exception est levée. J'ai besoin d'obtenir ces informations d'exception sur la méthode d'appel ( Method1)
Y a-t-il une manière dont je peux attraper cette exception en Method1ce qu'elle est lancée Method2?
Dans .NET 4 et supérieur, vous pouvez utiliser la Task<T>classe au lieu de créer un nouveau thread. Ensuite, vous pouvez obtenir des exceptions en utilisant la .Exceptionspropriété sur votre objet de tâche. Il y a 2 façons de le faire:
Dans une méthode distincte: // Vous traitez l'exception dans le thread de certaines tâches
Désolé mais j'ai oublié de mentionner que j'utilise .NET 3.5. Selon ma compréhension, la tâche est une chose 4.0?
Silverlight Student
2
@SilverlightStudent Ok, je viens de mettre à jour ma réponse pour répondre à vos exigences.
oxilumin
@oxilumin: Merci et beaucoup apprécié. Encore une question complémentaire. Si votre méthode Test () prend également quelques arguments, comment allez-vous modifier la méthode SafeExecute pour ces arguments?
Étudiant Silverlight
2
@SilverlightStudent Dans ce cas, je passerai un lambda au lieu de Test. J'aime() => Test(myParameter1, myParameter2)
oxilumin
2
@SilverlightStudent: mis à jour.
oxilumin
9
Vous ne pouvez pas intercepter l'exception dans Method1. Vous pouvez, cependant, intercepter l'exception dans Method2 et l'enregistrer dans une variable que le thread d'exécution d'origine peut ensuite lire et utiliser.
Merci pour votre réponse. Donc, si Method1 fait partie de Class1 et que j'ai une variable de type Exception dans cette classe. Chaque fois que Method2 lève une exception, elle définit également cette variable d'exception dans Class1. Cela ressemble-t-il à un design juste? Existe-t-il des meilleures pratiques pour gérer ce scénario?
Silverlight Student
Correct, il vous suffit de stocker l'exception et d'y accéder plus tard. Il n'est pas rare que les méthodes exécutées à l'avenir (en particulier les rappels lorsque la méthode 2 est terminée) rejettent ensuite cette exception comme si elles l'avaient elles-mêmes provoquée, mais cela dépend vraiment de ce que vous voulez.
ermau
0
La méthode la plus simple pour partager des données entre différents threads est shared datala suivante (certaines sont du pseudo-code):
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;}}
Vous pouvez lire à propos de cette méthode dans cette belle introduction sur le multithreading , cependant, j'ai préféré lire à ce sujet dans le O'Reilly book C# 3.0 in a nutshell, par les frères Albahari (2007), qui est également librement accessible sur Google Books, tout comme la nouvelle version du livre, car il couvre également le pool de threads, les threads de premier plan par rapport aux threads d'arrière-plan, etc., avec un exemple de code simple et agréable. (Avertissement: je possède un exemplaire usé de ce livre)
Dans le cas où vous créez une application WinForms, l'utilisation de données partagées est particulièrement pratique, car les contrôles WinForm ne sont pas thread-safe. En utilisant un rappel pour transmettre les données du thread de travail à un contrôle WinForm, le thread d'interface utilisateur principal a besoin d'un code laid Invoke()pour rendre ce contrôle thread-safe. En utilisant des données partagées à la place, et le thread unique System.Windows.Forms.Timer, avec un court Intervalde par exemple 0,2 seconde, vous pouvez facilement envoyer des informations du thread de travail au contrôle sans Invoke.
J'ai eu un problème particulier en ce sens que je voulais utiliser des éléments, contenant des contrôles, à partir d'une suite de tests d'intégration, donc je dois créer un thread STA. Le code avec lequel j'ai abouti est le suivant, mis ici au cas où d'autres auraient le même problème.
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){...}
Il s'agit d'un collage direct du code tel quel. Pour d'autres utilisations, je recommanderais de fournir une action ou une fonction en tant que paramètre et de l'invoquer sur le thread au lieu de coder en dur la méthode appelée.
Test
. J'aime() => Test(myParameter1, myParameter2)
Vous ne pouvez pas intercepter l'exception dans Method1. Vous pouvez, cependant, intercepter l'exception dans Method2 et l'enregistrer dans une variable que le thread d'exécution d'origine peut ensuite lire et utiliser.
la source
La méthode la plus simple pour partager des données entre différents threads est
shared data
la suivante (certaines sont du pseudo-code):Vous pouvez lire à propos de cette méthode dans cette belle introduction sur le multithreading , cependant, j'ai préféré lire à ce sujet dans le
O'Reilly book C# 3.0 in a nutshell
, par les frères Albahari (2007), qui est également librement accessible sur Google Books, tout comme la nouvelle version du livre, car il couvre également le pool de threads, les threads de premier plan par rapport aux threads d'arrière-plan, etc., avec un exemple de code simple et agréable. (Avertissement: je possède un exemplaire usé de ce livre)Dans le cas où vous créez une application WinForms, l'utilisation de données partagées est particulièrement pratique, car les contrôles WinForm ne sont pas thread-safe. En utilisant un rappel pour transmettre les données du thread de travail à un contrôle WinForm, le thread d'interface utilisateur principal a besoin d'un code laid
Invoke()
pour rendre ce contrôle thread-safe. En utilisant des données partagées à la place, et le thread uniqueSystem.Windows.Forms.Timer
, avec un courtInterval
de par exemple 0,2 seconde, vous pouvez facilement envoyer des informations du thread de travail au contrôle sansInvoke
.la source
J'ai eu un problème particulier en ce sens que je voulais utiliser des éléments, contenant des contrôles, à partir d'une suite de tests d'intégration, donc je dois créer un thread STA. Le code avec lequel j'ai abouti est le suivant, mis ici au cas où d'autres auraient le même problème.
Il s'agit d'un collage direct du code tel quel. Pour d'autres utilisations, je recommanderais de fournir une action ou une fonction en tant que paramètre et de l'invoquer sur le thread au lieu de coder en dur la méthode appelée.
la source