了解多執行緒 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中文網其他相關文章!