C#Threads

Ceci est un exemple implémentant deux exemples de threading en C#. Vous pourrez comparer par vous-mêmes avec des programmes équivalents dans les langages que vous connaissez.

Pour représenter un signal d'arrêt, nous utiliserons une petite classe Signal maison, encapsulant un signal booléen (pas ce qu'il y a de plus souple, soit, mais ça fera le boulot pour le moment).

Notez le recours à une propriété bool encapsulant un attribut volatile bool. En effet :

  • En C#, au moment d'écrire ceci, il n'est pas permis d'écrire une propriété volatile
  • Le recours au mot volatile ici est nécessaire pour que le compilateur soit informé du besoin de faire en sorte que les accès sur le booléen soient synchronisés. En effet, un accès concurrent par au moins deux fils d'exécution sur un même objet (pris au sens large du terme, et incluant les primitifs) sans synchronisation entraîne une Data Race, et ces bogues sont extrêmement méchants
  • Il est toutefois possible d'enrober un attribut volatile bool (donc ayant les bonnes propriétés pour ce qui est de la synchronisation) dans une propriété bool
using System;
using System.Threading;

namespace TiPoints
{
   class Signal
   {
      private volatile bool reçu;
      public bool Reçu
      {
         get { return reçu; }
         set { reçu = value; }
      }
   }

Une classe TiPoints représentera, avec sa méthode d'instance Exécuter(), l'acte d'afficher un petit point à la console jusqu'à ce qu'un signal d'arrêt lui soit envoyé.

   class TiPoints
   {
      private Signal signal;
      public TiPoints(Signal signal)
      {
         this.signal = signal ?? throw new ArgumentException();
      }
      public void Exécuter()
      {
         while (!signal.Reçu)
         {
            Console.Write(".");
            Thread.Sleep(1000);
         }
      }
   }

Un thread en C# est un délégué sur une méthode void ne recevant pas de paramètre. Dans le programme principal, nous en voyons deux exemples simples :

  • la méthode ExempleA() utilise la méthode d'instance Exécuter() d'un TiPoints à titre de thread, et lit une touche dans le code ayant lancé ce thread, puis attend sa complétion (invocation de Join(), comme dans le monde POSIX); et
  • la méthode ExempleB() utilise la méthode de classe LireTouche() à titre de thread, ce qui impose (dans ce cas-ci) le recours à un Signal accessible à une telle méthode.

Concrètement, on choisira l'approche qui nous convient.

   class Program
   {
      static void ExempleA()
      {
         Signal signal = new Signal();
         TiPoints tp = new TiPoints(signal);
         Thread th = new Thread(tp.Exécuter);
         th.Start();
         Console.ReadLine();
         signal.Reçu = true;
         th.Join();
      }
      static Signal g_signal = new Signal();
      static void LireTouche()
      {
         Console.ReadLine();
         g_signal.Reçu = true;
      }
      static void ExempleB()
      {
         TiPoints tp = new TiPoints(g_signal);
         Thread th = new Thread(LireTouche);
         th.Start();
         tp.Exécuter();
         th.Join();
      }
      static void Main(string[] args)
      {
         Console.WriteLine("Exemple avec délégué sur une méthode d'instance");
         ExempleA();
         Console.WriteLine("Exemple avec délégué sur une méthode de classe");
         ExempleB();
      }
   }
}

Valid XHTML 1.0 Transitional

CSS Valide !