| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente |
| lang:csharp:thread [2019/01/11 14:08] – Ajout de la note concernant le bordel entre thread. root | lang:csharp:thread [2020/05/11 00:51] (Version actuelle) – Fix alignement des images root |
|---|
| |
| =====Blocage inter-threads===== | =====Blocage inter-threads===== |
| [[https://stackoverflow.com/questions/2214002/how-to-get-return-value-when-begininvoke-invoke-is-called-in-c-sharp|How to get return value when BeginInvoke/Invoke is called in C#]] {{ :lang:csharp:thread:net_-_how_to_get_return_value_when_begininvoke_invoke_is_called_in_c_-_stack_overflow.mhtml |Archive du 21/11/2018}} | [[https://stackoverflow.com/questions/2214002/how-to-get-return-value-when-begininvoke-invoke-is-called-in-c-sharp|How to get return value when BeginInvoke/Invoke is called in C#]] {{ :lang:csharp:thread:net_-_how_to_get_return_value_when_begininvoke_invoke_is_called_in_c_-_stack_overflow_2020-02-07_10_22_03_am_.html |Archive du 06/02/2010 le 07/02/2020}} |
| ====Sans aideur==== | ====Sans aideur==== |
| ===Sans valeur de retour=== | ===Sans valeur de retour=== |
| |
| ====Thread classique==== | ====Thread classique==== |
| <note important> | <WRAP center round important 60%> |
| D'une manière générale, je déconseille l'utilisation de méthode lambda dès que la méthode doit accéder à des éléments extérieurs au contenu de la fonction lambda (''this'' par exemple). Cela pour bien avoir conscience des risques de race condition et de la traditionnelle erreur ''Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.''. | D'une manière générale, je déconseille l'utilisation de méthode lambda dès que la méthode doit accéder à des éléments extérieurs au contenu de la fonction lambda (''this'' par exemple). Cela pour bien avoir conscience des risques de race condition et de la traditionnelle erreur ''Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.''. |
| |
| {{ :lang:csharp:thread:invalidoperationexception.png?452 |}} | {{:lang:csharp:thread:invalidoperationexception.png|}} |
| |
| Donc pour que chaque Thread reste bien indépendant, je conseille une classe statique contenant une seule méthode statique, qui sera celle appelée. | Donc pour que chaque Thread reste bien indépendant, je conseille une classe statique contenant une seule méthode statique, qui sera celle appelée. |
| </note> | </WRAP> |
| |
| <code csharp> | <code csharp> |
| =====Threads accédant aux composants d'une form===== | =====Threads accédant aux composants d'une form===== |
| Il faut arrêter les threads accédant aux composants d'une Form avant de la détruire. Sinon, des exceptions vont être générées. | Il faut arrêter les threads accédant aux composants d'une Form avant de la détruire. Sinon, des exceptions vont être générées. |
| | |
| | La solution la plus simple est d'autoriser l'arrêt brutale des threads avec ''t.IsBackground = true;''. |
| | |
| | Mais si on souhaite un arrêt non brutal des threads, on peut utiliser la classe ci-dessous. |
| | |
| | On crée un ''ManageThread'' par ''Form''. On y met dedans tous les threads à exécuter via ''Add''. La méthode ''Add'' démarre automatiquement le thread si l'ajout a été un succès. |
| | |
| | A la fermeture de la fenêtre, on appelle la méthode ''JoinAllThreads'' qui empêche l'ajout de nouveaux threads et attend que chaque thread en cours (qu'il gère) termine son exécution. |
| |
| <file csharp ManageThread.cs> | <file csharp ManageThread.cs> |
| // Travail à faire. | // Travail à faire. |
| }); | }); |
| t.IsBackground = true; | // Si besoin, on peut vérifier si le thread a démarré. |
| if (manageThread.Add(t)) | manageThread.Add(t); |
| { | |
| t.Start(); | |
| } | |
| | |
| private void Form1_FormClosed(object sender, FormClosedEventArgs e) | private void Form1_FormClosed(object sender, FormClosedEventArgs e) |
| |
| =====Threads lambda utilisant une variable locale===== | =====Threads lambda utilisant une variable locale===== |
| [[https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop-variable-considered-harmful/|Closing over the loop variable considered harmful]] {{ :lang:csharp:thread:closing_over_the_loop_variable_considered_harmful_fabulous_adventures_in_coding.mhtml |Archive du 03/12/2018}} | [[https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop-variable-considered-harmful/|Closing over the loop variable considered harmful]] {{ :lang:csharp:thread:closing_over_the_loop_variable_considered_harmful_microsoft_docs_2020-02-07_10_22_10_am_.html |Archive du 12/11/2009 le 07/02/2020}} |
| |
| Mauvais : | Mauvais : |
| </code> | </code> |
| |
| Autre possibilité (non totalement identique en cas de nombreux threads en parallèle) : utilisation de Parallel.For. | |
| <code csharp> | <code csharp> |
| Parallel.For(0, 2, | Parallel.For(0, 2, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, |
| i => | i => |
| { | { |
| ); | ); |
| </code> | </code> |
| | Il est important de préciser le nombre maxi de threads sinon, si la charge baisse lors de l'accès à un fichier à cause d'un disque dur un peu lent, on peut se retrouver avec des dizaines de threads entraînant une saturation de la mémoire. |