var userList = new List<UserModel> { ... };
var tempCls = new TempClass();
foreach (var u in userList) {
tempCls.um = u; // 共享同一實例!
ThreadPool.QueueUserWorkItem(_ => tempCls.ShowMessage(null));
}
tempCls 單例,所有線程並發訪問 um 字段 → 數據競爭。foreach 循環變量 u 在 C# 5.0+ 中每次迭代創建新副本,但此處賦值給共享字段,非閉包捕獲問題,而是寫入共享字段的順序不確定。foreach (var u in userList) {
var user = u; // 顯式捕獲(舊版本必要)
ThreadPool.QueueUserWorkItem(_ => {
var localCls = new TempClass { um = user }; // 每任務一實例
localCls.ShowMessage(null);
});
}
var tasks = userList.Select(u => Task.Run(() => {
var cls = new TempClass { um = u };
cls.ShowMessage(null);
})).ToArray();
await Task.WhenAll(tasks); // 等待全部完成
Parallel.ForEach(userList, u => {
var cls = new TempClass { um = u };
cls.ShowMessage(null);
});
| 維度 | 調試模式 | 發布運行 |
|---|---|---|
| 線程調度 | 單步控制,順序確定 | OS 搶佔式,隨機交錯 |
| 優化 | 禁用優化 (Debug) | JIT 優化,指令重排 |
| 內存模型 | 隱式屏障較多 | 需顯式 volatile/lock/Interlocked |
| 現象 | 看似「正常」 | 數據錯亂、崩潰、死鎖 |
lock) / 無鎖 (ConcurrentDictionary, Interlocked) / Actor 模式。Task/async-await 替代手動線程池,異常傳播更自然。「調試正常、運行亂套」是多線程 Bug 的經典特徵。根因非調試器,而是代碼存在數據競爭。將共享對象 tempCls 改為任務局部實例,消除可變共享狀態,即可獲得確定性結果。