【问题标题】:Launching a thread from a loop and passing Loop ID从循环中启动线程并传递循环 ID
【发布时间】:2009-09-14 20:17:36
【问题描述】:

我今天刚开始玩线程,遇到了一些我不明白的东西。

public void Main()
{ 
    int maxValue = 5;
    for (int ID = 0; ID < maxValue; ID++)
    {
        temp(ID);
    }
}

public void temp(int i)
{
    MessageBox.Show(i.ToString());
}

尽可能基本的工作正常,但是当我尝试为每个线程创建一个新线程时,它只传递了 maxValue。请忽略这样做有多糟糕,我只是把它写成一个简单的例子。

public void Main()
{ 
    int maxValue = 5;
    for (int ID = 0; ID < maxValue; ID++)
    {
        threads.Add(new Thread(() => temp(myString, rowID)));
        threads[rowID].Start();
    }
}

public void temp(string myString, int i)
{
    string _myString = myString;

    MessageBox.Show(i.ToString());
}

鉴于此,我有两个问题: 1) 为什么没有在传递 ID 的新线程上调用该方法? 2) 这应该如何正确编码?

【问题讨论】:

  • 首先,您有未声明的 rowID 变量。将这两个事件重命名为 ID,它将正常工作。以下答案已过时!
  • rowID 是一个错字。如果将其更改为 ID 则不起作用 Jons 的答案是正确的。
  • @mnn:不会。您对捕获的变量在 C# 中的工作方式有多熟悉?
  • Jon Skeet:AFAIK 值类型与匿名委托一样保存,所以没问题。

标签: c# multithreading loops


【解决方案1】:

问题是您只有一个ID 变量,并且它正在被捕获。只有在实际执行新线程中的代码时,该变量才会被读取,这通常是在您的主线程完成其循环之后,将ID 留在maxValue。在每次循环迭代时复制一份,以便每次捕获不同的变量:

for (int ID = 0; ID < maxValue; ID++)
{
    int copy = ID;
    threads.Add(new Thread(() => temp(myString, copy)));
    threads[rowID].Start();
}

这是闭包的常见错误。阅读my article comparing C# and Java closures 了解更多信息。顺便说一句,foreach 也会发生同样的事情 - 这更令人困惑,因为它读取就像你每次都有一个新变量:

foreach (string url in urls)
{
    // Aargh, bug! Don't do this!
    new Thread(() => Fetch(url)).Start();
}

同样,您最终只会得到一个变量。您需要每个委托捕获一个单独的变量,因此您再次使用副本:

foreach (string url in urls)
{
    string urlCopy = url;
    new Thread(() => Fetch(urlCopy)).Start();
}

【讨论】:

  • 你犯了和 DataPimp 一样的错误。您不需要其他变量,只需将 rowID 重命名为 ID 即可。
  • 非常感谢,我不确定我是否理解 100% 为什么我发布的第一个代码被执行但第二个没有(我想这有点道理)但我肯定会阅读那篇文章你的,希望这能澄清事情。
  • @mnn:不会。您最终会遇到捕获的变量问题。它可能不会总是显示,但你肯定会遇到错误。在启动线程时使用捕获的循环变量非常容易出错。我假设rowID 的使用只是一个错字,因为使用未声明的变量是编译时间 错误而不是执行时间 错误。
猜你喜欢
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 2013-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多