Multithreading C#
Thread est défini comme le chemin d'exécution du programme. Chaque thread définit un flux de contrôle unique. Si votre application implique des opérations complexes et chronophages, il est souvent avantageux de configurer différents chemins d'exécution des threads, chaque thread effectuant un travail spécifique.
Les threads sont des processus légers. Un 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 permet d’économiser des cycles CPU inutiles tout en augmentant l’efficacité des applications.
Le programme que nous avons écrit jusqu'à présent est un seul thread exécuté comme un processus unique de l'instance en cours d'exécution de l'application. Cependant, cette sous-application ne peut effectuer qu'une seule tâche à la fois. Afin d'effectuer plusieurs tâches simultanément, il peut être divisé en threads plus petits.
Cycle de vie du thread
Le cycle de vie du 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 du thread sont répertoriés ci-dessous :
État non démarré : lorsque l'instance de thread est créée mais que la méthode Start a pas La condition lors de l'appel.
État prêt : La condition dans laquelle un thread est prêt à s'exécuter et attend les cycles du processeur.
Statut inopérant : Le fil de discussion est inutilisable dans les situations suivantes :
La méthode de veille a été appelée
La méthode d'attente a été appelée
Bloquée par une opération d'E/S
Statut de mort : La condition dans laquelle un thread a terminé son exécution ou a été terminé.
Main Thread
En C#, la classe System.Threading.Thread est utilisée pour le travail des threads. Il permet la création et l'accès à des threads individuels dans des applications multithread. Le premier thread à exécuter dans le processus est appelé thread principal.
Lorsque le programme C# démarre son exécution, le thread principal est automatiquement créé. Les threads créés à l'aide de la classe Thread sont appelés par les threads enfants du thread principal. Vous pouvez accéder aux threads en utilisant la propriété CurrentThread de la classe Thread.
Le programme suivant démontre l'exécution du thread principal :
using System; 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 produira les résultats suivants :
This is MainThread
Classe de thread communément Attributs et méthodes utilisés
Le tableau suivant répertorie certains attributs couramment utilisés de la classe Thread :
属性 | 描述 |
---|---|
CurrentContext | 获取线程正在其中执行的当前上下文。 |
CurrentCulture | 获取或设置当前线程的区域性。 |
CurrentPrinciple | 获取或设置线程的当前负责人(对基于角色的安全性而言)。 |
CurrentThread | 获取当前正在运行的线程。 |
CurrentUICulture | 获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。 |
ExecutionContext | 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。 |
IsAlive | 获取一个值,该值指示当前线程的执行状态。 |
IsBackground | 获取或设置一个值,该值指示某个线程是否为后台线程。 |
IsThreadPoolThread | 获取一个值,该值指示线程是否属于托管线程池。 |
ManagedThreadId | 获取当前托管线程的唯一标识符。 |
Name | 获取或设置线程的名称。 |
Priority | 获取或设置一个值,该值指示线程的调度优先级。 |
ThreadState | 获取一个值,该值包含当前线程的状态。 |
Le tableau suivant répertorie quelques méthodes couramment utilisées de la classe Thread :
Numéro de série | Nom et description de la méthode |
---|---|
1 | public void Abort( ) Lance une ThreadAbortException sur le thread appelant cette méthode pour 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() Allouer des emplacements de données sans nom sur tous les threads. Pour de meilleures performances, utilisez plutôt les champs marqués avec l’attribut ThreadStaticAttribute. |
3 | public statique LocalDataStoreSlot AllocateNamedDataSlot(
nom de chaîne) Allouez des emplacements de données nommés sur tous les threads. Pour de meilleures performances, utilisez plutôt les champs marqués avec l’attribut ThreadStaticAttribute. |
4 | public static void BeginCriticalRegion() Avertit l'hôte que l'exécution est sur le point d'entrer dans une zone de code dans laquelle le thread se termine Ou l'impact d'une exception non gérée peut nuire à d'autres tâches dans le domaine d'application. |
5 | public static void BeginThreadAffinity() Notifie le code géré par l'hôte qu'il est sur le point d'exécuter un thread qui dépend de l’identité de l’instruction physique actuelle du système d’exploitation. |
6 | public static void EndCriticalRegion() Avertit l'hôte que l'exécution est sur le point d'entrer dans une zone de code dans laquelle le thread se termine Ou les exceptions non gérées n'affectent que la tâche en cours. |
7 | public static void EndThreadAffinity() Notifier l'hôte que le code géré a fini de s'exécuter dépend de l'identité de l'hôte actuel instructions de thread du système d’exploitation physique. |
8 | public static void FreeNamedDataSlot(string name) Élimine l'association entre le nom et l'emplacement pour tous les threads du processus . Pour de meilleures performances, utilisez plutôt les champs marqués avec l’attribut ThreadStaticAttribute. |
9 | Objet statique public GetData(
Emplacement LocalDataStoreSlot
) Récupère une valeur de l'emplacement spécifié sur le thread actuel dans le domaine actuel du thread actuel. Pour de meilleures performances, utilisez plutôt les champs marqués avec l’attribut ThreadStaticAttribute. |
10 | public static AppDomain GetDomain() Renvoie le domaine actuel dans lequel le thread actuel est en cours d'exécution. |
11 | public static AppDomain GetDomainID() Renvoie un identifiant de domaine d'application unique. |
12 | public statique LocalDataStoreSlot GetNamedDataSlot(
nom de chaîne
) Trouvez un emplacement de données nommé. Pour de meilleures performances, utilisez plutôt les champs marqués avec l’attribut ThreadStaticAttribute. |
13 | public void Interrupt() Interrompre le thread dans l'état du thread WaitSleepJoin. |
14 | public void Join() Bloque le thread appelant jusqu'à ce que l'un des threads se termine tandis que le traitement standard de la pompe à messages COM et SendMessage se poursuit. Il existe différentes surcharges de cette méthode. |
15 | public static void MemoryBarrier() Synchronisez l'accès à la mémoire comme suit : Le processeur exécutant le thread en cours Lorsque les instructions sont réorganisées , l'accès à la mémoire après l'appel MemoryBarrier ne peut pas être effectué en premier, puis l'accès à la mémoire avant l'appel à MemoryBarrier. |
16 | public static void ResetAbort() Annuler l'abandon demandé pour le fil de discussion en cours. |
17 | public static void SetData(
Emplacement LocalDataStoreSlot,
Données d'objet
) Définissez les données dans l'emplacement spécifié pour le domaine actuel de ce fil sur le fil en cours d'exécution. Pour de meilleures performances, utilisez plutôt les champs marqués avec l’attribut ThreadStaticAttribute. |
18 | public void Start() Démarrer un fil de discussion. |
19 | public statique vide Sommeil(
int millisecondesTimeout
) Laissez le fil s'arrêter un moment. |
20 | public static void SpinWait(
itérations int
) fait attendre le thread pendant la durée définie par le paramètre itérations. |
21 | octet statique public VolatileRead(
adresse d'octet de référence
) double statique publique VolatileRead( réf double adresse ) public static int VolatileRead( adresse de référence ) Objet statique public VolatileRead( Adresse de l'objet ref ) Lire la valeur du champ. Cette valeur est la valeur la plus récente écrite par n'importe quel processeur de l'ordinateur, quel que soit le nombre de processeurs ou l'état du cache du processeur. Il existe différentes surcharges de cette méthode. Seuls quelques formulaires sont donnés ici. |
22 | public static void VolatileWrite(
adresse d'octet de référence,
valeur d'octet
) public static void VolatileWrite( réf double adresse, valeur double ) public static void VolatileWrite( ref int adresse, valeur entière ) public static void VolatileWrite( ref Adresse de l'objet, Valeur de l'objet ) Écrit immédiatement une valeur dans un champ, rendant la valeur visible à tous les processeurs de l'ordinateur. Il existe différentes surcharges de cette méthode. Seuls quelques formulaires sont donnés ici. |
23 | public static bool Yield() Fait en sorte que le thread appelant exécute un autre thread prêt à s'exécuter sur le thread actuel. processeur. Le système d'exploitation sélectionne le thread à exécuter. |
Création de fils de discussion
Les fils de discussion sont créés en étendant la classe Thread. La classe Thread étendue appelle la méthode Start() pour démarrer l'exécution du thread enfant.
Le programme suivant illustre ce concept :
using System; 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
Gestion des threads
La classe Thread fournit diverses méthodes de gestion des threads.
L'exemple suivant montre l'utilisation de la méthode sleep(), qui est utilisée pour mettre un fil de discussion en pause à un moment précis.
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { Console.WriteLine("Child thread starts"); // 线程暂停 5000 毫秒 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 produira les résultats suivants :
In Main: Creating the Child thread Child thread starts Child Thread Paused for 5 seconds Child thread resumes
Détruire le fil
Abort() la méthode est utilisé Détruire le fil.
Abandonnez un thread au moment de l'exécution en lançant threadabortexception. Cette exception ne peut pas être interceptée. S'il y a un bloc finally, le contrôle sera envoyé au bloc finally.
Le programme suivant illustre ceci :
using System; using System.Threading; namespace MultithreadingApplication { class ThreadCreationProgram { public static void CallToChildThread() { try { Console.WriteLine("Child thread starts"); // 计数到 10 for (int counter = 0; counter <= 10; counter++) { Thread.Sleep(500); Console.WriteLine(counter); } Console.WriteLine("Child Thread Completed"); } catch (ThreadAbortException e) { Console.WriteLine("Thread Abort Exception"); } finally { Console.WriteLine("Couldn't catch the Thread Exception"); } } 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(); // 停止主线程一段时间 Thread.Sleep(2000); // 现在中止子线程 Console.WriteLine("In Main: Aborting the Child thread"); 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 Exception