对 C# 循环中的多线程感到困惑 [重复]

Posted

技术标签:

【中文标题】对 C# 循环中的多线程感到困惑 [重复]【英文标题】:Confused about multi-threading in a loop for C# [duplicate] 【发布时间】:2012-03-08 07:11:31 【问题描述】:

可能重复:C# Captured Variable In Loop

我对多线程编程很陌生。 当我运行下面的代码时,只有最后一个孩子被执行。 有人能告诉我发生了什么吗? 非常感谢。

private void Process()

    Dictionary<int, int> dataDict = new Dictionary<int, int>();
    dataDict.Add(1, 2000);
    dataDict.Add(2, 1000);
    dataDict.Add(3, 4000);
    dataDict.Add(4, 3000);

    foreach (KeyValuePair<int, int> kvp in dataDict)
    
        Console.WriteLine("Ready for [" + kvp.Key.ToString() + "]");
        Task.Factory.StartNew(() => DoSomething(kvp.Value, kvp.Key));
    

private static void DoSomething(int waitTime, int childID)

                   
        Console.WriteLine("Start task [" + childID.ToString() + "]");
        Thread.Sleep(waitTime);
        Console.WriteLine("End task [" + childID.ToString() + "]");
    


输出


Ready for [1]
Ready for [2]
Ready for [3]
Ready for [4]
Start task [4]
Start task [4]
Start task [4]
Start task [4]
End task [4]
End task [4]
End task [4]
End task [4]

【问题讨论】:

【参考方案1】:

通过在 lambda 中使用循环变量,所有变量都有效地引用同一个变量,这是它们运行时字典的最后一项。

在将循环变量传递给 lambda 之前,您需要将循环变量分配给循环本地的另一个变量。这样做:

foreach (KeyValuePair<int, int> kvp in dataDict)

    var pair = kvp;
    Console.WriteLine("Ready for [" + pair.Key.ToString() + "]");
    Task.Factory.StartNew(() => DoSomething(pair.Value, pair.Key));

编辑:这个小陷阱似乎在 C#5 中得到修复。这就是为什么它可能对其他人有用;)请参阅 labroo 的评论

【讨论】:

人们应该真正解释他们为什么投反对票,这对我来说似乎是一个合理的解释 为什么要投反对票,我不知道这是否是解决方案,但这是一个有效的改变......blogs.msdn.com/b/ericlippert/archive/2009/11/12/… 我也想知道。看不出我的回答有什么问题。 顺便说一句,Botz3000 的回答暗示的是所有线程都在运行......但是,当它们有机会运行时,kvp == 4 我也想过,但我就是不明白为什么。【参考方案2】:

您可以通过将 kvp 分配给 for 循环中的局部变量并将变量字段 Key 和 Value 传递给 DoSomething 方法来防止这种行为。

【讨论】:

谢谢。我也想到了,但我就是不明白为什么。

以上是关于对 C# 循环中的多线程感到困惑 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

foreach循环中的多线程C#

SQLite中的多线程数据写入[重复]

如何安全地终止线程? (使用指针)C++

C#中的多线程启动画面?

第13章 C#中的多线程

对 C# 6.0 中的字符串插值感到困惑 [重复]