lang:csharp:thread
Ceci est une ancienne révision du document !
Table des matières
Instruction lock
lock
permet d'empêcher deux threads d'exécuter un code entouré de l'objet verrouillé. Attention, lock
distingue uniquement des threads différents. Un lock(x)
dans un lock(x)
dans un même thread ne pose pas de problème, le deuxième lock
n'étant pas bloquant.
Blocage inter-threads
Sans aideur
Sans valeur de retour
public static void readControlText(Control varControl) { if (varControl.InvokeRequired) { varControl.Invoke((Action)delegate {readControlText(varControl);})); } else { // Faire ce qu'il faut. } }
Avec valeur de retour
public static string readControlText(Control varControl) { if (varControl.InvokeRequired) { return (string)varControl.Invoke( new Func<String>(() => readControlText(varControl)) ); } else { // Renvoyer ce qu'il faut. return ""; } }
Avec aideur
Sans valeur de retour
/// <summary> /// Aideur pour appeler une action soit directement, soit depuis un Invoke si nécessaire. /// </summary> /// <param name="control">Le controleur nécessitant l'Invoke.</param> /// <param name="action">L'action a exécuter.</param> public static void AutoInvokeAction(Control control, Action action) { if (control.InvokeRequired) { control.Invoke((Action)delegate { action(); }); } else { action(); } } AutoInvokeAction(wiz, () => { wiz.Focus(); });
/// <summary> /// Aideur pour appeler une fonction soit directement, soit depuis un Invoke si nécessaire. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="control">Le controleur nécessitant l'Invoke.</param> /// <param name="function">La fonction a exécuter.</param> /// <returns>Le retour de la fonction.</returns> public static T AutoInvokeFunc<T>(Control control, Func<T> function) { if (control.InvokeRequired) { return (T)control.Invoke(new Func<T>(() => function())); } else { return function(); } } return AutoInvokeFunc(control, () => { return true; });
Création des threads
Thread classic avec lambda expression
gistfile1.cs Archive du 23/11/2018
Thread t = new Thread(() => { // Action à faire }); t.Start();
ou directement :
new Thread(() => { // Action à faire }).Start();
Thread se répétant
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.
- ManageThread.cs
public class ManageThread { /// <summary> /// Stockage de tous les threads. /// </summary> private List<Thread> allThreads = new List<Thread>(); /// <summary> /// Autorise ou pas les ajout de threads. /// Quand ManageThread est en train de purger tous les threads (via JoinAllThreads()), /// on empêche l'ajout de nouveaux. /// </summary> private bool allowAdd = true; /// <summary> /// On ajoute un thread à la liste. /// En même temps, on s'assure sur tous les threads de la liste sont bien en vie. /// </summary> /// <param name="t">Le nouveau thread.</param> 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; } } /// <summary> /// On attend que tous les threads restants s'arrêtent tout seul. /// Si une fonction parallèle en ajoute aussi en boucle, on ne quitte jamais la fonction. /// </summary> 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 :
public partial class Form1 : Form { private ManageThread manageThread = new ManageThread(); Thread t = new Thread(() => { // Travail à faire. }); t.IsBackground = true; if (manageThread.Add(t)) { t.Start(); } 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
Closing over the loop variable considered harmful Archive du 03/12/2018
Mauvais :
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 :
for (int i = 0; i < 2; i++) { // Variable locale. int j = i; Thread t = new Thread(() => { Console.WriteLine(j); }); t.Start(); }
Autre possibilité (non totalement identique en cas de nombreux threads en parallèle) : utilisation de Parallel.For.
Parallel.For(0, 2, i => { Console.WriteLine(i); } );
lang/csharp/thread.1543848595.txt.gz · Dernière modification : 2018/12/03 15:49 de root