了解多线程 C# 中的 foreach 循环和闭包
C# 中的多线程在使用 foreach
循环和闭包时会带来复杂性。 当 foreach
循环内的闭包引用循环的迭代变量时,就会出现问题。
考虑这个例子:
<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>
这里,每个线程的闭包捕获对单个 f
变量的引用。 随着循环的进行,f
的值会发生变化,从而导致不可预测的结果 - 线程可能会对意外的 Foo
对象进行操作。
确保线程安全
为了避免这种情况,请在每次迭代中创建一个新的局部变量:
<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>
现在,每个线程都有自己独立的引用 (f2
),确保在正确的 DoSomething()
实例上调用 Foo
。
C# 5 及更高版本
C# 5 及更高版本中的行为略有变化。 编译器将 foreach
变量视为在循环范围内有效声明的变量,即使它出现在循环范围之外。 因此,上面的两个代码片段在 C# 5 及后续版本中都是线程安全的。 然而,为了清晰度和向后兼容性,显式副本仍然是良好的做法。
以上是为什么 Foreach 循环和闭包需要在多线程 C# 代码中进行特殊处理?的详细内容。更多信息请关注PHP中文网其他相关文章!