Maison développement back-end Tutoriel C#.Net Introduction détaillée aux exemples de code graphique de synchronisation de threads C#

Introduction détaillée aux exemples de code graphique de synchronisation de threads C#

Mar 08, 2017 am 11:14 AM
c# 线程同步

Cet article présente principalement les connaissances pertinentes sur la synchronisation des threads en C#. Il a une très bonne valeur de référence, jetons-y un œil avec l'éditeur ci-dessous

Avant-propos

Lorsqu'un thread du pool de threads est bloqué, le pool de threads créera des threads supplémentaires, et la création, la destruction et la planification de threads nécessitent des ressources mémoire assez coûteuses. De plus, de nombreux développeurs ont l'habitude de créer plus de threads lorsqu'ils voient que les threads de leurs programmes ne font rien d'utile pour créer des threads évolutifs et évolutifs. programmes réactifs, nous avons présenté l'explication détaillée de la programmation asynchrone C# avant

Cependant, il existe également de sérieux problèmes dans la programmation asynchrone si deux threads différents accèdent aux mêmes variables et données, selon l'implémentation de notre fonction asynchrone, non Il peut y avoir deux threads accédant aux mêmes données en même temps. Dans ce cas, nous avons besoin d'une synchronisation des threads. Lorsque plusieurs threads accèdent aux données partagées en même temps, la synchronisation des threads peut empêcher la corruption des données. La raison pour laquelle le concept de simultanéité est mis en avant est que l'essence de la synchronisation des threads est une question de timing.

Asynchrone et synchrone sont relatifs. La synchronisation signifie une exécution séquentielle. Après en avoir exécuté une, vous devez attendre et coordonner l'exécution de la suivante. Asynchrone signifie qu'ils sont indépendants les uns des autres et continuent de faire leurs propres choses en attendant un événement. Il n'est pas nécessaire d'attendre la fin de l'événement avant de travailler à nouveau. Les threads sont un moyen de devenir asynchrone. Asynchrone signifie que le thread principal qui appelle la méthode n'a pas besoin d'attendre la fin d'un autre thread de manière synchrone, afin que le thread principal puisse faire autre chose.

Constructions primitives en mode utilisateur et en mode noyau

Concepts de base

Primitives : Oui Constructions simples utilisées dans le code

Mode utilisateur : en coordonnant les threads via des instructions spéciales du processeur, le système d'exploitation ne détecte jamais un blocage de thread sur une construction primitive en mode utilisateur.

Mode Kernel : Fournies par Windows lui-même, les fonctions implémentées par le noyau sont appelées dans le thread de l'application.

Constructions en mode utilisateur

Constructions volatiles

Le compilateur C#, le compilateur JIT et les processeurs optimiser le code, et ils essaient de s'assurer que nos intentions sont conservées. Cependant, d'un point de vue multi-thread, nos intentions peuvent ne pas être conservées :

 static void Main(string[] args)
 {
 Console.WriteLine("让worker函数运行5s后停止");
 var t = new Thread(Worker);
 t.Start();
 Thread.Sleep(5000);
 stop = true;
 Console.ReadLine();
 }
 private static bool stop = false;
 private static void Worker(object obj)
 {
 int x = 0;
 while (!stop)
 {
 x++;
 }
 Console.WriteLine("worker函数停止x={0}",x);
 }
Copier après la connexion
< 🎜. >

Si le compilateur vérifie que stop est faux, il génère du code pour entrer dans une boucle infinie et continue d'incrémenter x dans la boucle, donc la boucle d'optimisation se termine rapidement, mais le compilateur ne détecte l'arrêt qu'une seule fois , pas à chaque fois.

Exemple 2---Deux threads accèdent simultanément :

class test
 {
 private static int m_flag = 0;
 private static int m_value = 0;
 public static void Thread1(object obj)
 {
 m_value = 5;
 m_flag = 1;
 }
 public static void Thread2(object obj)
 {
 if (m_flag == 1)
 Console.WriteLine("m_value = {0}", m_value);
 }
 //多核CPU机器才会出现线程同步问题
 public void Exec()
 {
 var thread1 = new Thread(Thread1);
 var thread2 = new Thread(Thread2);
 thread1.Start();
 thread2.Start();
 Console.ReadLine();
 }
 }
Copier après la connexion

Lorsque le programme est exécuté, le compilateur doit changer la variable m_flag et m_value sont lus de la RAM dans le registre du processeur. La RAM transmet d'abord la valeur de m_value 0, et thread1 change la valeur en 5, mais thread2 ne sait pas que thread2 pense toujours que la valeur est 0. De manière générale, ce problème est plus probable. se produit dans les processeurs multicœurs, plus il y a de processeurs, plus il y a de chances que plusieurs threads accèdent aux ressources en même temps.

Le mot-clé volatile désactive certaines optimisations effectuées par le compilateur C#, le compilateur JTP et le CPU. S'il est appliqué à une variable, le champ ne pourra pas être mis en cache dans le registre du CPU, garantissant ainsi la lecture et l'écriture de celui-ci. le terrain est en sécurité. Faites-le dans la RAM.

Construction de verrouillage

Chaque méthode de la classe System.Threading.Interlocked effectue une opération de lecture et d'écriture atomique avant d'appeler une méthode Interlocked. Toutes les écritures de variables sont effectuées avant cet appel à la méthode Interlocked, et toutes les lectures de variables après l'appel sont effectuées après cet appel.

La méthode Interlocked effectue principalement des opérations statiques sur les variables INT32 telles que Add, Decrement, Compare, Exchange, CompareChange et d'autres méthodes, et accepte également les paramètres d'objet, Double et d'autres types.

Opération atomique : fait référence à une opération qui ne sera pas interrompue par le mécanisme de planification des threads ; une fois cette opération démarrée, elle s'exécutera jusqu'à la fin sans aucun changement de contexte (passage à un autre thread) au milieu.

Démonstration de code :

Description : interrogez de manière asynchrone plusieurs serveurs Web via la méthode Interlocked et renvoyez des données en même temps, et les résultats ne sont exécutés qu'une seule fois.

//上报状态类型
 enum CoordinationStatus
 {
 Cancel,
 Timeout,
 AllDone
 }
Copier après la connexion

class AsyncCoordinator
 {
 //AllBegun 内部调用JustEnded来递减它
 private int _mOpCount = 1;
 //0=false,1=true
 private int _mStatusReported = 0;
 private Action<CoordinationStatus> _mCallback;
 private Timer _mTimer;
 //发起一个操作之前调用
 public void AboutToBegin(int opsToAdd = 1)
 {
 Interlocked.Add(ref _mOpCount, opsToAdd);
 }
 //处理好一个操作的结果之后调用
 public void JustEnded()
 {
 if (Interlocked.Decrement(ref _mOpCount) == 0)
 {
 ReportStatus(CoordinationStatus.AllDone);
 } 
 }
 //该方法必须在发起所有操作后调用
 public void AllBegin(Action<CoordinationStatus> callback, int timeout = Timeout.Infinite)
 {
 _mCallback = callback;
 if (timeout != Timeout.Infinite)
 {
 _mTimer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
 JustEnded();
 }
 }
 private void TimeExpired(object o)
 {
 ReportStatus(CoordinationStatus.Timeout);
 }
 public void Cancel()
 {
 ReportStatus(CoordinationStatus.Cancel);
 }
 private void ReportStatus(CoordinationStatus status)
 {
 //如果状态从未报告过,就报告它,否则就忽略它,只调用一次
 if (Interlocked.Exchange(ref _mStatusReported, 1) == 0)
 {
 _mCallback(status);
 } 
 }
 }
Copier après la connexion

class MultiWebRequest
 {
 //辅助类 用于协调所有的异步操作
 private AsyncCoordinator _mac = new AsyncCoordinator();
 protected Dictionary<string,object> _mServers = new Dictionary<string, object>
 {
 {"http://www.baidu.com",null},{"http://www.Microsoft.com",null},{"http://www.cctv.com",null},
 {"http://www.souhu.com",null},{"http://www.sina.com",null},{"http://www.tencent.com",null},
 {"http://www.youku.com",null}
 };
 private Stopwatch sp;
 public MultiWebRequest(int timeout = Timeout.Infinite)
 {
 sp = new Stopwatch();
 sp.Start();
 //通过异步方式一次性发起请求
 var httpclient = new HttpClient();
 foreach (var server in _mServers.Keys)
 {
 _mac.AboutToBegin(1);
 httpclient.GetByteArrayAsync(server).ContinueWith(task => ComputeResult(server, task));
 }
 _mac.AllBegin(AllDone,timeout);
 Console.WriteLine("");
 }
 private void ComputeResult(string server, Task<Byte[]> task)
 {
 object result;
 if (task.Exception != null)
 {
 result = task.Exception.InnerException;
 }
 else
 {
 //线程池处理IO
 result = task.Result.Length;
 }
 //保存返回结果的长度
 _mServers[server] = result;
 _mac.JustEnded();
 }
 public void Cancel()
 {
 _mac.Cancel();
 }
 private void AllDone(CoordinationStatus status)
 {
 sp.Stop();
 Console.WriteLine("响应耗时总计{0}",sp.Elapsed);
 switch (status)
 {
 case CoordinationStatus.Cancel:
  Console.WriteLine("操作取消");
  break;
 case CoordinationStatus.AllDone:
  Console.WriteLine("操作完成,完成的结果如下");
  foreach (var server in _mServers)
  {
  Console.WriteLine("{0}",server.Key);
  object result = server.Value;
  if (result is Exception)
  {
  Console.WriteLine("错误原因{0}",result.GetType().Name);
  }
  else
  {
  Console.WriteLine("返回字节数为:{0}",result);
  }
  }
  break;
 case CoordinationStatus.Timeout:
  Console.WriteLine("操作超时");
  break;
 default:
  throw new ArgumentOutOfRangeException("status", status, null);
 }
 }
 }
Copier après la connexion

Il est fortement recommandé de se référer au code ci-dessus. Je ferai souvent référence à ce modèle lors de l'accès au serveur.

Verrouillage rotatif simple

class SomeResource
 {
 private SimpleSpinLock s1 = new SimpleSpinLock();
 public void AccessResource()
 {
 s1.Enter();
 //一次是有一个线程才能进入访问
 s1.Leave();
 }
 }
 class SimpleSpinLock
 {
 private int _mResourceInUse;
 public void Enter()
 {
 while (true)
 {
 if(Interlocked.Exchange(ref _mResourceInUse,1)==0)
  return;
 }
 }
 public void Leave()
 {
 Volatile.Write(ref _mResourceInUse,1);
 }
 }
Copier après la connexion

Il s'agit d'une implémentation simple d'un verrou de synchronisation de thread, le plus grand Le problème avec les verrous est que lorsqu'il y a concurrence, le thread "tourne", ce qui fera perdre un temps précieux au processeur et empêchera le processeur d'effectuer plus de travail. Par conséquent, ce type de verrou tournant doit être utilisé pour protéger ceux-ci. exécution de code très rapide.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Active Directory avec C# Active Directory avec C# Sep 03, 2024 pm 03:33 PM

Guide d'Active Directory avec C#. Nous discutons ici de l'introduction et du fonctionnement d'Active Directory en C# ainsi que de la syntaxe et de l'exemple.

Générateur de nombres aléatoires en C# Générateur de nombres aléatoires en C# Sep 03, 2024 pm 03:34 PM

Guide du générateur de nombres aléatoires en C#. Nous discutons ici du fonctionnement du générateur de nombres aléatoires, du concept de nombres pseudo-aléatoires et sécurisés.

Modificateurs d'accès en C# Modificateurs d'accès en C# Sep 03, 2024 pm 03:24 PM

Guide des modificateurs d'accès en C#. Nous avons discuté de l'introduction Types de modificateurs d'accès en C# ainsi que d'exemples et de résultats.

Vue Grille de données C# Vue Grille de données C# Sep 03, 2024 pm 03:32 PM

Guide de la vue Grille de données C#. Nous discutons ici des exemples de la façon dont une vue de grille de données peut être chargée et exportée à partir de la base de données SQL ou d'un fichier Excel.

Sérialisation C# Sérialisation C# Sep 03, 2024 pm 03:30 PM

Guide de sérialisation C#. Nous discutons ici de l'introduction, des étapes de l'objet de sérialisation C#, du fonctionnement et de l'exemple respectivement.

Modèles en C# Modèles en C# Sep 03, 2024 pm 03:33 PM

Guide des modèles en C#. Nous discutons ici de l'introduction et des 3 principaux types de modèles en C# ainsi que de ses exemples et de l'implémentation du code.

Nombres premiers en C# Nombres premiers en C# Sep 03, 2024 pm 03:35 PM

Guide des nombres premiers en C#. Nous discutons ici de l'introduction et des exemples de nombres premiers en c# ainsi que de l'implémentation du code.

Factorielle en C# Factorielle en C# Sep 03, 2024 pm 03:34 PM

Guide de Factorial en C#. Nous discutons ici de l'introduction de factorial en c# ainsi que de différents exemples et de l'implémentation du code.

See all articles