C# Multithreading
ThreadUn thread est défini comme le chemin d'exécution d'un programme. Chaque thread définit un flux de contrôle unique. Si votre application implique des opérations complexes et chronophages, il est souvent bénéfique de définir différents chemins d'exécution de threads, chaque thread effectuant un travail spécifique.
Thread estProcessus légerUn exemple courant d'utilisation de threads est la mise en œuvre de la programmation parallèle dans les systèmes d'exploitation modernes. L'utilisation de threads évite le gaspillage de cycles CPU et améliore l'efficacité des applications.
Les programmes que nous avons écrits jusqu'à présent s'exécutent comme un processus unique avec un seul thread comme instance d'exécution de l'application. Cependant, de cette manière, l'application ne peut exécuter qu'une seule tâche à la fois. Pour exécuter plusieurs tâches simultanément, elle peut être divisée en threads plus petits.
Cycle de vie d'un thread
Le cycle de vie d'un thread commence lorsqu'un objet de la classe System.Threading.Thread est créé, et se termine lorsque le thread est terminé ou termine son exécution.
Les différents états du cycle de vie d'un thread sont listés ci-dessous :
- État non démarré: État lorsqu'une instance de thread a été créée mais que la méthode Start n'a pas été appelée.
- État prêt: État lorsqu'un thread est prêt à s'exécuter et attend un cycle CPU.
- État non exécutable: Un thread n'est pas exécutable dans les cas suivants :
- La méthode Sleep a été appelée
- La méthode Wait a été appelée
- Bloqué par une opération d'E/S
- État mort: État lorsque le thread a terminé son exécution ou a été avorté.
thread principal
En C#,System.Threading.ThreadLa classe Thread est utilisée pour le travail sur les threads. Elle permet de créer et d'accéder à des threads individuels dans une application multithread. Le premier thread exécuté dans un processus est appelé thread principal.thread principal。
Lorsqu'un programme C# commence son exécution, le thread principal est automatiquement créé. En utilisantThread, les threads créés par la classe sont appelés threads enfants du thread principal. Vous pouvez utiliser la propriétéCurrentThreadde la classe Thread pour accéder au thread.
Le programme suivant démontre l'exécution du thread principal :
Exemple
using System.Threading;
namespace MultithreadingApplication
{
class MainThreadProgram
{
static void Main(string[] args)
{
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :
This is MainThread
Propriétés et méthodes courantes de la classe Thread
Le tableau ci-dessous répertorieThreadquelques méthodes courantes de la classePropriété:
| Propriété | Description |
|---|---|
| CurrentContext | Obtient le contexte actuel dans lequel le thread s'exécute. |
| CurrentCulture | Obtient ou définit la culture du thread actuel. |
| CurrentPrincipal | Obtient ou définit le principal actuel du thread (pour la sécurité basée sur les rôles). |
| CurrentThread | Obtient le thread en cours d'exécution. |
| CurrentUICulture | Obtient ou définit la culture actuelle utilisée par le gestionnaire de ressources pour rechercher des ressources spécifiques à la culture au moment de l'exécution. |
| ExecutionContext | Obtient un objet ExecutionContext qui contient des informations contextuelles sur le thread actuel. |
| IsAlive | Obtient une valeur qui indique l'état d'exécution du thread actuel. |
| IsBackground | Obtient ou définit une valeur indiquant si un thread est un thread d'arrière-plan. |
| IsThreadPoolThread | Obtient une valeur indiquant si un thread appartient au pool de threads managé. |
| ManagedThreadId | Obtient l'identificateur unique du thread managé actuel. |
| Name | Obtient ou définit le nom du thread. |
| Priorité | Obtient ou définit une valeur indiquant la priorité de planification du thread. |
| ThreadState | Obtient une valeur qui contient l'état du thread actuel. |
Le tableau ci-dessous répertorieThreadquelques méthodes courantes de la classeMéthodes:
| Numéro de série | Nom de la méthode et description |
|---|---|
| 1 | public void Abort() Lève une ThreadAbortException sur le thread sur lequel cette méthode est appelée, afin de commencer le processus de terminaison de ce thread. L'appel de cette méthode termine généralement le thread. |
| 2 | public static LocalDataStoreSlot AllocateDataSlot() Alloue un emplacement de données sans nom sur tous les threads. Pour de meilleures performances, utilisez plutôt des champs marqués avec l'attribut ThreadStaticAttribute. |
| 3 | public static LocalDataStoreSlot AllocateNamedDataSlot(
string name)
Alloue un emplacement de données nommé sur tous les threads. Pour de meilleures performances, utilisez plutôt des champs marqués avec l'attribut ThreadStaticAttribute. |
| 4 | public static void BeginCriticalRegion() Signale à l'hôte que l'exécution est sur le point d'entrer dans une région de code où les effets des abandons de threads ou des exceptions non gérées peuvent compromettre d'autres tâches dans le domaine d'application. |
| 5 | public static void BeginThreadAffinity() Signale à l'hôte que du code managé est sur le point d'exécuter des instructions qui dépendent de l'identité du thread de système d'exploitation physique actuel. |
| 6 | public static void EndCriticalRegion() Signale à l'hôte que l'exécution est sur le point d'entrer dans une région de code dans laquelle les abandons de threads ou les exceptions non gérées affectent uniquement la tâche actuelle. |
| 7 | public static void EndThreadAffinity() Notifie l'hôte que le code managé a terminé l'exécution d'instructions qui dépendent de l'identité du thread de système d'exploitation physique actuel. |
| 8 | public static void FreeNamedDataSlot(string name) Élimine l'association entre les noms et les emplacements pour tous les threads du processus. Pour de meilleures performances, utilisez plutôt des champs marqués avec l'attribut ThreadStaticAttribute. |
| 9 | public static Object GetData(
LocalDataStoreSlot slot
)
Récupère la valeur à partir de l'emplacement spécifié sur le thread actuel, dans le domaine actuel du thread actuel. Pour de meilleures performances, utilisez plutôt des champs marqués avec l'attribut ThreadStaticAttribute. |
| 10 | public static AppDomain GetDomain() Renvoie le domaine actuel dans lequel le thread actuel s'exécute. |
| 11 | public static AppDomain GetDomainID() Renvoie un identificateur unique de domaine d'application. |
| 12 | public static LocalDataStoreSlot GetNamedDataSlot(
string name
)
Recherche un emplacement de données nommé. Pour de meilleures performances, utilisez plutôt des champs marqués avec l'attribut ThreadStaticAttribute. |
| 13 | public void Interrupt() Interrompt un thread qui se trouve dans l'état de thread WaitSleepJoin. |
| 14 | public void Join() Bloque le thread appelant jusqu'à ce qu'un thread se termine, tout en continuant à effectuer le pompage de messages COM et SendMessage standard. Cette méthode a différentes formes de surcharge. |
| 15 | public static void MemoryBarrier() Synchronise l'accès à la mémoire comme suit : le processeur exécutant le thread actuel ne peut pas réorganiser les instructions de telle sorte que les accès mémoire après l'appel à MemoryBarrier s'exécutent avant les accès mémoire antérieurs à l'appel à MemoryBarrier. |
| 16 | public static void ResetAbort() Annule l'Abort demandé pour le thread actuel. |
| 17 | public static void SetData(
LocalDataStoreSlot slot,
Object data
)
Définit des données dans l'emplacement spécifié sur le thread en cours d'exécution pour le domaine actuel du thread. Pour de meilleures performances, utilisez plutôt des champs marqués avec l'attribut ThreadStaticAttribute. |
| 18 | public void Start() Démarre un thread. |
| 19 | public static void Sleep(
int millisecondsTimeout
)
Suspend le thread pendant une période de temps. |
| 20 | public static void SpinWait(
int iterations
)
Fait attendre un thread pendant la durée définie par le paramètre iterations. |
| 21 | public static byte VolatileRead(
ref byte address
) public static double VolatileRead( ref double address ) public static int VolatileRead( ref int address ) public static Object VolatileRead( ref Object address ) Lit la valeur du champ. Quel que soit le nombre de processeurs ou l'état du cache du processeur, la valeur est la dernière valeur écrite par n'importe quel processeur de l'ordinateur. Cette méthode a différentes formes de surcharge. Seules certaines formes sont données ici. |
| 22 | public static void VolatileWrite(
ref byte address,
byte value
) public static void VolatileWrite( ref double address, double value ) public static void VolatileWrite( ref int address, int value ) public static void VolatileWrite( ref Object address, Object value ) Écrit immédiatement une valeur dans un champ afin que la valeur soit visible par tous les processeurs de l'ordinateur. Cette méthode a différentes formes de surcharge. Seules quelques formes sont données ici. |
| 23 | public static bool Yield() Amène le thread appelant à exécuter un autre thread qui est prêt à s'exécuter sur le processeur actuel. Le thread à exécuter est sélectionné par le système d'exploitation. |
Création de threads
Les threads sont créés en étendant la classe Thread. La classe Thread étendue appelle la méthodeStart()pour démarrer l'exécution du thread enfant.
Le programme suivant démontre ce concept :
Exemple
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :
In Main: Creating the Child thread Child thread starts
Gérer les threads
La classe Thread fournit diverses méthodes pour gérer les threads.
L'exemple suivant illustresleep()Utilisation de la méthode pour suspendre un thread pendant une durée spécifiée.
Exemple
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
// Mettre le thread en pause pendant 5000 millisecondes
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds",
sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :
In Main: Creating the Child thread Child thread starts Child Thread Paused for 5 seconds Child thread resumes
Destruction des threads
Abort()est une méthode utilisée pour détruire le thread.
En lançantthreadabortexceptionInterrompt le thread à l'exécution. Cette exception ne peut pas être interceptée. S'il y a unfinallybloc, le contrôle est transféré àfinallyBloc.
Le programme suivant illustre ceci :
Exemple
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts");
// Compter jusqu'à 10
for (int counter = 0; counter <= 10; counter++)
{
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Thread enfant terminé");
}
catch (ThreadAbortException e)
{
Console.WriteLine("Exception d'abandon de thread");
}
finally
{
Console.WriteLine("Impossible d'intercepter l'exception de thread");
}
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
// Mettre en pause le thread principal pendant un certain temps
Thread.Sleep(2000);
// Maintenant, abandonner le thread enfant
Console.WriteLine("Dans Main : abandon du thread enfant");
childThread.Abort();
Console.ReadKey();
}
}
}
Lorsque le code ci-dessus est compilé et exécuté, il produit les résultats suivants :
In Main: Creating the Child thread Child thread starts 0 1 2 In Main: Aborting the Child thread Thread Abort Exception Couldn't catch the Thread Exceptionautres extensions