从循环启动一个线程并传递Loop ID

时间:2009-09-14 20:17:36

标签: c# multithreading loops

我刚刚开始玩线程,我遇到了一些我不理解的东西。

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)如何正确编码?

1 个答案:

答案 0 :(得分:9)

问题是你只有一个ID变量,而且它被捕获了。当新线程中的代码实际执行时,该变量只是 read ,这通常是在主线程完成其循环之后,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();
}