Comprendre les boucles et les fermetures foreach en C# multithread
Le multithreading en C# peut introduire des complexités lors de l'utilisation de foreach
boucles et fermetures. Le problème survient lorsqu'une fermeture dans une boucle foreach
fait référence à la variable d'itération de la boucle.
Considérez cet exemple :
<code class="language-csharp">var threads = new List<Thread>(); foreach (Foo f in ListOfFoo) { Thread thread = new Thread(() => f.DoSomething()); threads.Add(thread); thread.Start(); }</code>
Ici, la fermeture de chaque fil capture une référence à l'unique f
variable. Au fur et à mesure que la boucle progresse, la valeur de f
change, conduisant à des résultats imprévisibles : les threads peuvent opérer sur des objets Foo
inattendus.
Assurer la sécurité des fils
Pour éviter cela, créez une nouvelle variable locale à chaque itération :
<code class="language-csharp">var threads = new List<Thread>(); foreach (Foo f in ListOfFoo) { Foo f2 = f; // Create a copy for each thread Thread thread = new Thread(() => f2.DoSomething()); threads.Add(thread); thread.Start(); }</code>
Maintenant, chaque thread a sa propre référence indépendante (f2
), garantissant que DoSomething()
est appelé sur la bonne Foo
instance.
C# 5 et au-delà
Le comportement a légèrement changé en C# 5 et versions ultérieures. Le compilateur traite la variable foreach
comme étant effectivement déclarée dans la portée de la boucle, même si elle apparaît à l'extérieur. Par conséquent, les deux extraits de code ci-dessus sont thread-safe en C# 5 et versions ultérieures. Cependant, la copie explicite reste une bonne pratique pour plus de clarté et de compatibilité ascendante.
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!