Tutoriel de programmation multithread C#

View more categories:

1- Le concept de multithreading (Multithreading)

Multithreading est un concept important dans les langages de programmation et C# aussi, ce qui est créé le flux du programme en cours d'exécution parallèle les uns aux autres. Pour plus de simplicité  , vous voyex un exemple suivant : 
HelloThread.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class HelloThread
    {
        public static void Main(string[] args)
        {
             
            Console.WriteLine("Create new Thread...\n");          

            // Crée un Thread enfant, qui s'exécute en parallèle avec le Thread principal.
            Thread newThread = new Thread(WriteB);

            Console.WriteLine("Start newThread...\n");

            // Activer l'exécution newThread.
            newThread.Start();

            Console.WriteLine("Call Write('-') in main Thread...\n");

            // Dans le thread principal, écrasez le caractère '-'
            for (int i = 0; i < 50; i++)
            {
                Console.Write('-');

                // Dormez (sleep)70 millisecondes.
                Thread.Sleep(70);
            }


            Console.WriteLine("Main Thread finished!\n");
            Console.Read();
        }



        public static void WriteB()
        {
            // Boucle 100 fois graver des caractères ''B"
            // ​​​​​​​
            for (int i = 0; i < 100; i++)
            {
                Console.Write('B');

                // Dormez 100 millisecondes
                Thread.Sleep(100);
            }
                
        }
    }

   
}
Et vous exécutez cette classe:
Le principe de fonctionnement du flux (fil) a expliqué seulement dans l'illustration ci-dessous :

2- Passer les paramètres à Thread

Ci-dessusvous vous êtes habitués avec l'exemple HelloThread , vous avez créé un objet enroulé autour de ( wrap ) une méthode statique pour exécuter cette méthode en parallèle au flux (fil) père.
 
 
La méthode statique peut devenir un paramètre au constructeur de la classe Thread si la méthode n'a pas paramètre, ou avoir un seul paramètre de type object .
// Une méthode statique, sans paramètre.
// ​​​​​​​
public static void LetGo()
{
      // ...
}

// Une méthode statique, n'a qu'un seul type de paramètre d'objet.
public static void GetGo(object value)
{
      // ...
}
L'exemple suivant, je vais créer un Thread qui est enroulé autour d'une méthode statique avec un paramètre (type d'objet). il exécute thread et transfert la valeur au paramètre.
MyWork.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class MyWork
    {

        public static void DoWork(object ch)
        {
            for (int i = 0; i < 100; i++)
            {
            	 
                Console.Write(ch);

                // Domez (sleep) 50 milliseconds.
                Thread.Sleep(50);
            }
        }



    }
}
ThreadParamDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadParamDemo
    {

        public static void Main(string[] args)
        { 

            Console.WriteLine("Create new thread.. \n");

            // Créez un objet Thread pour envelopper (wrap) la méthode statique MyWork.DoWork
            Thread workThread = new Thread(MyWork.DoWork);

            Console.WriteLine("Start workThread...\n");

            // Exécutez workThread,
            // et transmettre le paramètre à la méthode MyWork.DoWork.
            workThread.Start("*");


            for (int i = 0; i < 20; i++)
            {
                Console.Write(".");

                // Dormez 30 secondes.
                Thread.Sleep(30);
            }

            Console.WriteLine("MainThread ends");
            Console.Read();
        }
    }

}
Exécutez la classe ThreadParamDemo:

3- Thread utilise une méthode non statique

Vous pouvez également créer un flux (fil) en utilisant des méthodes conventionnelles. Voyez l'exemple
Worker.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class Worker
    {
        private string name;
        private int loop;

        public Worker(string name, int loop)
        {
            this.name = name;
            this.loop = loop;
        }

        public void DoWork(object value)
        {
            for (int i = 0; i < loop; i++)
            {
                Console.WriteLine(name + " working " + value);
                Thread.Sleep(50);
            }
             
        }

    }

}
WorkerTest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class WorkerTest
    {

        public static void Main(string[] args)
        {
            Worker w1 = new Worker("Tran",10);

            // Create a Thread object.
            Thread workerThread1 = new Thread(w1.DoWork);

            // Pass parameter to DoWork method.
            workerThread1.Start("A");


            Worker w2 = new Worker("Marry",15);

            // Create a Thread object.
            Thread workerThread2 = new Thread(w2.DoWork);

            // Pass parameter to DoWork method.
            workerThread2.Start("B"); 
          
            Console.Read();
        }
    }

}
Exécutez l'exemple:

4- ThreadStart Delegate

ThreadStart une classe déléguée (délégué). Et il est passé en tant que paramètre pour initialiser l'objet  Thread .
 
Avec .Net <2.0, pour démarrer (start) à un flux (fil), vous devez créer ThreadStart, il est un délégué. 

À partir de la version 2.0 du .NET Framework, n'est pas nécessaire de créer un objet accrédité (ThreadStart) explicitement. Vous devez seulement spécifier le nom de la méthode dans le constructeur du Thread.
Programmer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class Programmer
    {
        private string name;
        public Programmer(string name)  
        {
            this.name= name;
        }

        // C'est une méthode non statique, pas de paramètres.
        public void DoCode()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(name + " codding ... ");
                Thread.Sleep(50);
            }
                
        }
    }

}
ThreadStartDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;


namespace MultithreadingTutorial
{
    class ThreadStartDemo
    {


        public static void Main(string[] args)
        {
            // Créez un objet ThreadStart qui enveloppe une méthode statique.
            // (il peut seulement envelopper les méthodes non paramétrique)
            // (Il est qu'un objet qui est autorisé à exécuter la méthode).
            ThreadStart threadStart1 = new ThreadStart(DoWork);

            // Créer un thread couvrant (wrap) threadStart1.
            Thread workThread = new Thread(threadStart1);

            // Appeler start thread
            workThread.Start();

            // Créer un objet  Programmer.
            Programmer tran = new Programmer("Tran");

            // Vous pouvez également créer un objet ThreadStart qui enveloppe une méthode non statique.
            // (ThreadStart ne peut que couvrir les méthodes sans paramètres)
            ThreadStart threadStart2 = new ThreadStart(tran.DoCode);

            // Créer  Thread enveloppe  threadStart2.
            Thread progThread = new Thread(threadStart2);

            progThread.Start();

            Console.WriteLine("Main thread ends");
            Console.Read();
        }


        public static void DoWork()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.Write("*");
                Thread.Sleep(100);
            }                
        }
    }

}
Exécutez l'exemple:

5- Thread avec un code anonyme

les parties au-dessus vous avez créé les  Thread en utilisant une méthode spécifique. Vous pouvez créer un thread pour exécuter un n'importe quel morceau de code.
// ​​​​​​​
// Utilisez delegate () pour créer une méthode anonyme.
delegate()
{
     //  ...
}
Exemple:
ThreadUsingSnippetCode.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadUsingSnippetCode
    {

        public static void Main(string[] args) 
        {

            Console.WriteLine("Create thread 1");

            // Crée un thread pour exécuter un code d'extrait.
            Thread newThread1 = new Thread(
                delegate()
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine("Code in delegate() " + i);
                        Thread.Sleep(50);
                    }

                }
            );

            Console.WriteLine("Start newThread1");

            
            // Start thread. 
            newThread1.Start();

            Console.WriteLine("Create thread 2");

            // Crée un thread pour exécuter un code d'extrait.
            Thread newThread2 = new Thread(
                delegate(object value)
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine("Code in delegate(object) " + i + " - " + value);
                        Thread.Sleep(100);
                    }

                }
            );

            Console.WriteLine("Start newThread2");

            // Commencez thread 2.
            // Transmettre la valeur à delegate().
            newThread2.Start("!!!");


            Console.WriteLine("Main thread ends");
            Console.Read();

        }
    }

}
Exécutez l'exemple:

6- Nomez pour Thread

Dans la programmation multithread , vous pouvez mettre un nom au flux (fil), il est vraiment utile en cas de débogage (débogage ), pour connaître le code qui est  exécuté dans le thread .

Dans un  thread, vous pouvez appeler  Thread.CurrentThread.Name pour récupérer le nom du flux est exécutés à ce moment-là.
Voyez l'exemple d'illustration:
NamingThreadDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class NamingThreadDemo
    {

        public static void Main(string[] args)
        {
            // Nommez le thread actuel
            // (En tant que thread principal).
            Thread.CurrentThread.Name = "Main";

            Console.WriteLine("Code of "+ Thread.CurrentThread.Name);

            Console.WriteLine("Create new thread");

            // Créez un  thread.
            Thread letgoThread = new Thread(LetGo);

            // Nommez ce thread.
            letgoThread.Name = "Let's Go";

            letgoThread.Start();

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Code of " + Thread.CurrentThread.Name);
                Thread.Sleep(30);
            }

            Console.Read();
        }


        public static void LetGo()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Code of " + Thread.CurrentThread.Name);
                Thread.Sleep(50);
            }
        }
    }

}
Exécutez l'exemple:

7- Priorité entre Thread

Dans C# il y a 5 niveaux de priorité d'un flux,  ils sont définis dans enum ThreadPriority.
** ThreadPriority enum **
enum ThreadPriority {
    Lowest,
    BelowNormal,
    Normal,
    AboveNormal,
    Highest
}
Habituellement avec des ordinateurs de haute vitesse, si le flux de faire uniquement la quantité de travail moins, vous êtes très difficiles de repérer la différence entre le débit d'écoulement hautement prioritaires et de faible priorités.

L'exemple ci-dessous comporte deux  flux, chaque flux imprime 100k lignes de texte (un nombre assez grand de voir la différence).
ThreadPriorityDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadPriorityDemo
    {
        private static DateTime endsDateTime1;
        private static DateTime endsDateTime2;


        public static void Main(string[] args)
        {
            endsDateTime1 = DateTime.Now;
            endsDateTime2 = DateTime.Now;

            Thread thread1 = new Thread(Hello1);

            // Définissez la priorité la plus élevée pour thread1
            thread1.Priority = ThreadPriority.Highest;

            Thread thread2 = new Thread(Hello2);

            // Définissez la priorité la plus basse pour thread2.
            thread2.Priority = ThreadPriority.Lowest;


            thread2.Start(); thread1.Start();

            Console.Read();
        }


        public static void Hello1()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("Hello from thread 1: "+ i);
            }
            // Le temps de thread1 se termine.
            endsDateTime1 = DateTime.Now;

            PrintInterval();
        }

        public static void Hello2()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("Hello from thread 2: "+ i);
            }
            // Le temps de thread2 se termine.
            endsDateTime2 = DateTime.Now;

            PrintInterval();
        }

        private static void PrintInterval()
        {
            // ​​​​​​​
            // Intervalle (Millisecondes)
            TimeSpan interval = endsDateTime2 - endsDateTime1;

 
            Console.WriteLine("Thread2 - Thread1 = " + interval.TotalMilliseconds + " milliseconds");
        }
    }

}
Exécutez l'exemple:

8- Utilisez Join()

Thread.Join () est une méthode qui a annoncé attendre ce thread terminé et le thread père était en cours d'exécution.
ThreadJoinDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;


namespace MultithreadingTutorial
{
    class ThreadJoinDemo
    {

        public static void Main(string[] args)
        {
            Console.WriteLine("Create new thread");

            Thread letgoThread = new Thread(LetGo); 
            
            // Commencer Thread (start thread).
            letgoThread.Start();

            // Dites au thread principal (voici Main principal)
            // Attendez que letgoThread finisse, puis continuez à fonctionner.
            letgoThread.Join();
            
            // Cette ligne de code doit attendre letgoThread terminé, puis exécutez.
            Console.WriteLine("Main thread ends");
            Console.Read();
        }


        public static void LetGo()
        {
            for (int i = 0; i < 15; i++)
            {
                Console.WriteLine("Let's Go " + i);
            }
        }
    }

}
Exécutez l'exemple:

9- Utilisez Yield()

En théorie, le "rendement" ("Yield") signifie donner, abandonné, se rendit. Un flux de rendement indique le système d'exploitation qu'il est disposé à laisser l'autre  thread planifié à sa place. Cela montre qu'il ne fait pas quelque chose de trop important. Notez qu'il est seulement une suggestion et n'est pas garanti d'être efficace à tous.
Donc la méthode de rendement () Yield()est utilisée lorsque vous vous voyez ce  thread qui est libre, il ne fait rien d'important, il suggère un système d'exploitation temporaire pour donner la priorité à d'autres flux.
L'exemple ci-dessous, il y a  deux flux, chaque flux imprime sur une ligne de texte 100k fois (nombres assez grand pour voir la différence). Un flux est l'éclair la plus haute priorité et un éclair flux au moins une priorité. Intervalle de temps de deux flux.
ThreadYieldDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadYieldDemo
    {

        private static DateTime importantEndTime;
        private static DateTime unImportantEndTime;

        public static void Main(string[] args)
        {
            importantEndTime = DateTime.Now;
            unImportantEndTime = DateTime.Now;

            Console.WriteLine("Create thread 1");

            Thread importantThread = new Thread(ImportantWork);

            // Définissez la priorité la plus élevée pour ce thread.
            importantThread.Priority = ThreadPriority.Highest; 

            Console.WriteLine("Create thread 2");

            Thread unImportantThread = new Thread(UnImportantWork);

            // Définissez la priorité la plus base pour ce thread..
            unImportantThread.Priority = ThreadPriority.Lowest; 

            // Start threads. 
            unImportantThread.Start();
            importantThread.Start();
           

            Console.Read();

        }

        // Un travail important qui nécessite une priorité élevée.
        public static void ImportantWork()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("\n Important work " + i); 

                // Annoncer du système d'exploitation
                // ce thread donne la priorité à d'autres threads.
                Thread.Yield();
            }
            // L'heure de fin de ce thread.
            importantEndTime = DateTime.Now;
            PrintTime();
        }

        public static void UnImportantWork()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("\n  -- UnImportant work " + i); 
            }
            // L'heure de fin de ce thread.
            unImportantEndTime = DateTime.Now;
            PrintTime();
        }

        private static void PrintTime()
        { 
            // Intervalle (Millisecondes)
            TimeSpan interval = unImportantEndTime - importantEndTime; 
      
            Console.WriteLine("UnImportant Thread - Important Thread = " + interval.TotalMilliseconds +" milliseconds");
        }
         
    }

}
Exécuter  une classe dans le cas où il n'y a aucun  Thread.rendement() ( Thread.Yield():)
Exécuter la classe au-dessus dans le cas le flux priorité plus élevée que pour appeler continuellement  Thread.rendement() ( Thread.Yield()) pour demander un système temporaire en faveur de la priorité sur l'autre flux.

10- TODO

View more categories: