我刚刚开始玩线程,我遇到了一些我不理解的东西。
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)如何正确编码?
答案 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();
}