Problèmes de sécurité des threads des boucles foreach
et des expressions Lambda en C#
Analysons l'extrait de code suivant :
<code class="language-csharp">foreach (Foo f in ListOfFoo) { Thread thread = new Thread(() => f.DoSomething()); threads.Add(thread); thread.Start(); }</code>
<code class="language-csharp">foreach (Foo f in ListOfFoo) { Foo f2 = f; Thread thread = new Thread(() => f2.DoSomething()); threads.Add(thread); thread.Start(); }</code>
Quel extrait de code garantit que chaque thread appelle une méthode sur l'instance Foo
dans la même itération de boucle que lors de la création du thread ?
En C# 5 et versions ultérieures, les deux extraits de code sont sécurisés en raison des modifications apportées par le compilateur aux définitions de variables dans les portées de fermeture. Cependant, avant C# 5, seul le deuxième extrait était sûr.
Dans le premier extrait de code, la variable f
est déclarée en dehors de la boucle et reste visible tout au long de l'exécution. Cela signifie qu'il n'y a qu'une seule instance de f
dans la portée de fermeture. Par conséquent, différents threads accédant à f
peuvent entrer en conflit, provoquant des erreurs d'invocation de méthode.
Pour atténuer ce problème, le deuxième extrait de code déclare une nouvelle variable f2
à l'intérieur de la boucle. Cela garantit que chaque portée de fermeture possède sa propre copie de la référence à l'instance Foo
, garantissant ainsi une exécution de méthode sécurisée par thread.
L'exemple suivant illustre ce problème :
<code class="language-csharp">static void Main() { int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; foreach (int i in data) { new Thread(() => Console.WriteLine(i)).Start(); } Console.ReadLine(); }</code>
Si les variables temporaires ne sont pas utilisées, ce code produira une sortie imprévisible et incorrecte. En effet, tous les threads font référence à la même variable i
et la valeur de foreach
est la dernière valeur après la fin de la boucle i
.
Par conséquent, pour garantir la sécurité des threads, il est préférable de toujours créer une copie d'une variable locale lors de l'utilisation d'une expression Lambda dans une boucle foreach
, comme indiqué dans le deuxième extrait de code.
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!