lang:csharp:thread
Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
| lang:csharp:thread [2018/11/21 17:24] – Ajout de "Invoke" root | lang:csharp:thread [2020/05/11 00:51] (Version actuelle) – Fix alignement des images root | ||
|---|---|---|---|
| Ligne 3: | Ligne 3: | ||
| =====Blocage inter-threads===== | =====Blocage inter-threads===== | ||
| - | ====Sans valeur de retour==== | + | [[https:// |
| + | ====Sans aideur==== | ||
| + | ===Sans valeur de retour=== | ||
| <code csharp> | <code csharp> | ||
| public static void readControlText(Control varControl) { | public static void readControlText(Control varControl) { | ||
| Ligne 15: | Ligne 17: | ||
| </ | </ | ||
| - | ====Avec valeur de retour==== | + | ===Avec valeur de retour=== |
| <code csharp> | <code csharp> | ||
| public static string readControlText(Control varControl) { | public static string readControlText(Control varControl) { | ||
| Ligne 29: | Ligne 31: | ||
| } | } | ||
| </ | </ | ||
| + | |||
| + | ====Avec aideur==== | ||
| + | ===Sans valeur de retour=== | ||
| + | <code csharp> | ||
| + | /// < | ||
| + | /// Aideur pour appeler une action soit directement, | ||
| + | /// </ | ||
| + | /// <param name=" | ||
| + | /// <param name=" | ||
| + | public static void AutoInvokeAction(Control control, Action action) | ||
| + | { | ||
| + | if (control.InvokeRequired) | ||
| + | { | ||
| + | control.Invoke((Action)delegate { action(); }); | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | action(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | AutoInvokeAction(wiz, | ||
| + | </ | ||
| + | <code csharp> | ||
| + | /// < | ||
| + | /// Aideur pour appeler une fonction soit directement, | ||
| + | /// </ | ||
| + | /// < | ||
| + | /// <param name=" | ||
| + | /// <param name=" | ||
| + | /// < | ||
| + | public static T AutoInvokeFunc< | ||
| + | { | ||
| + | if (control.InvokeRequired) | ||
| + | { | ||
| + | return (T)control.Invoke(new Func< | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | return function(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | return AutoInvokeFunc(control, | ||
| + | </ | ||
| + | |||
| + | =====Création des threads===== | ||
| + | |||
| + | ====Thread classique==== | ||
| + | <WRAP center round important 60%> | ||
| + | D'une manière générale, je déconseille l' | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Donc pour que chaque Thread reste bien indépendant, | ||
| + | </ | ||
| + | |||
| + | <code csharp> | ||
| + | public static class Simulation | ||
| + | { | ||
| + | // Pas de risque de race condition, la valeur est modifiée | ||
| + | // par une seule ligne de code extérieure et n'est pas modifiée par Execution(). | ||
| + | public static long finSimul; | ||
| + | |||
| + | public static void Execution() | ||
| + | { | ||
| + | } | ||
| + | } | ||
| + | |||
| + | new Thread(new ThreadStart(Simulation.Execution)).Start(); | ||
| + | </ | ||
| + | |||
| + | ====Thread classique avec lambda expression==== | ||
| + | [[https:// | ||
| + | <code csharp> | ||
| + | Thread t = new Thread(() => | ||
| + | { | ||
| + | // Action à faire | ||
| + | }); | ||
| + | t.Start(); | ||
| + | </ | ||
| + | |||
| + | ou directement : | ||
| + | <code csharp> | ||
| + | new Thread(() => | ||
| + | { | ||
| + | // Action à faire | ||
| + | }).Start(); | ||
| + | </ | ||
| + | |||
| + | ====Thread se répétant==== | ||
| + | <code csharp> | ||
| + | date = new System.Threading.Timer( | ||
| + | (state) => | ||
| + | { | ||
| + | // Faire ce qu'on veut. | ||
| + | }, | ||
| + | this, 0, 1000); // Toutes les 1000 millisecondes. | ||
| + | </ | ||
| + | |||
| + | =====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. | ||
| + | |||
| + | La solution la plus simple est d' | ||
| + | |||
| + | Mais si on souhaite un arrêt non brutal des threads, on peut utiliser la classe ci-dessous. | ||
| + | |||
| + | On crée un '' | ||
| + | |||
| + | A la fermeture de la fenêtre, on appelle la méthode '' | ||
| + | |||
| + | <file csharp ManageThread.cs> | ||
| + | public class ManageThread | ||
| + | { | ||
| + | /// < | ||
| + | /// Stockage de tous les threads. | ||
| + | /// </ | ||
| + | private List< | ||
| + | |||
| + | /// < | ||
| + | /// Autorise ou pas les ajout de threads. | ||
| + | /// Quand ManageThread est en train de purger tous les threads (via JoinAllThreads()), | ||
| + | /// on empêche l' | ||
| + | /// </ | ||
| + | private bool allowAdd = true; | ||
| + | |||
| + | /// < | ||
| + | /// On ajoute un thread à la liste. | ||
| + | /// En même temps, on s' | ||
| + | /// </ | ||
| + | /// <param name=" | ||
| + | public bool Add(Thread t) | ||
| + | { | ||
| + | lock (allThreads) | ||
| + | { | ||
| + | for (int i = allThreads.Count - 1; i >= 0; i--) | ||
| + | { | ||
| + | if (!allThreads[i].IsAlive) | ||
| + | { | ||
| + | allThreads.RemoveAt(i); | ||
| + | } | ||
| + | } | ||
| + | if (!allowAdd) | ||
| + | return false; | ||
| + | allThreads.Add(t); | ||
| + | return true; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /// < | ||
| + | /// On attend que tous les threads restants s' | ||
| + | /// Si une fonction parallèle en ajoute aussi en boucle, on ne quitte jamais la fonction. | ||
| + | /// </ | ||
| + | public void JoinAllThreads() | ||
| + | { | ||
| + | lock (allThreads) | ||
| + | { | ||
| + | allowAdd = false; | ||
| + | } | ||
| + | while (true) | ||
| + | { | ||
| + | Thread t; | ||
| + | lock (allThreads) | ||
| + | { | ||
| + | if (allThreads.Count == 0) | ||
| + | return; | ||
| + | t = allThreads[0]; | ||
| + | } | ||
| + | t.Join(); | ||
| + | lock (allThreads) | ||
| + | { | ||
| + | // Pas RemoveAt(0). | ||
| + | allThreads.Remove(t); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Utilisation : | ||
| + | <code csharp> | ||
| + | public partial class Form1 : Form | ||
| + | { | ||
| + | private ManageThread manageThread = new ManageThread(); | ||
| + | | ||
| + | Thread t = new Thread(() => | ||
| + | { | ||
| + | // Travail à faire. | ||
| + | }); | ||
| + | // Si besoin, on peut vérifier si le thread a démarré. | ||
| + | manageThread.Add(t); | ||
| + | | ||
| + | private void Form1_FormClosed(object sender, FormClosedEventArgs e) | ||
| + | { | ||
| + | // Ici, on arrête éventuellement tous les threads ajoutant des threads à manageThread. | ||
| + | manageThread.JoinAllThreads(); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | =====Threads lambda utilisant une variable locale===== | ||
| + | [[https:// | ||
| + | |||
| + | Mauvais : | ||
| + | <code csharp> | ||
| + | for (int i = 0; i < 2; i++) | ||
| + | { | ||
| + | Thread t = new Thread(() => | ||
| + | { | ||
| + | // i vaudra toujours 2 car le thread sera appelé après la boucle. | ||
| + | Console.WriteLine(i); | ||
| + | }); | ||
| + | t.Start(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Bon : | ||
| + | <code csharp> | ||
| + | for (int i = 0; i < 2; i++) | ||
| + | { | ||
| + | // Variable locale. | ||
| + | int j = i; | ||
| + | Thread t = new Thread(() => | ||
| + | { | ||
| + | Console.WriteLine(j); | ||
| + | }); | ||
| + | t.Start(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code csharp> | ||
| + | Parallel.For(0, | ||
| + | i => | ||
| + | { | ||
| + | Console.WriteLine(i); | ||
| + | } | ||
| + | ); | ||
| + | </ | ||
| + | Il est important de préciser le nombre maxi de threads sinon, si la charge baisse lors de l' | ||
lang/csharp/thread.1542817459.txt.gz · Dernière modification : de root
