类似的问题被问到here,但答案通常都与lambda符号有关。没有lambda我得到了类似的结果,所以我想我要求澄清一下:
说我有这样的事情:
for (int i = 0; i < 5; i++)
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + i);
}))).Start();
可以预期以下输出:
Thread 0
Thread 1
Thread 2
Thread 3
Thread 4
现在我意识到线程没有以任何特定的顺序启动,所以我们假设上面的行可以按任何顺序出现。
但事实并非如此。 而是发生了什么:
Thread 3
Thread 4
Thread 4
Thread 4
Thread 4
或类似的东西,这使我相信,如果我,它传递的是参考,而不是传递值。 (这很奇怪,因为int是值类型)。
做这样的事情:
for (int i = 0; i < 5; i++)
(new Thread(new ThreadStart(delegate()
{
int j = i;
Console.WriteLine("Thread " + j);
}))).Start();
也没有帮助,即使我们已经复制了i。我假设原因是它没有及时复制我。
做这样的事情:
for (int i = 0; i < 5; i++)
{
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + i);
}))).Start();
Thread.Sleep(50);
}
似乎解决了这个问题,但是由于我们每次迭代都浪费了50ms,所以非常不受欢迎,更不用说如果计算机负载很重,那么50ms可能还不够。
以下是我当前特定问题的示例:
Thread t = new Thread(new ThreadStart(delgate()
{
threadLogic(param1, param2, param3, param4);
}));
t.Start();
param1 = param2 = param3 = param4 = null;
使用:
void threadLogic(object param1, object param2, object param3, object param4)
{
// Do some stuff here...
}
我希望threadLogic()在自己的线程中运行,但是上面的代码给出了一个空引用异常。我假设这是因为在线程有机会启动之前将值设置为null。
再次,将Thread.Sleep(100)设置为有效,但从各个方面来看都是一个糟糕的解决方案。 对于这种特殊类型的竞争条件,你们有什么建议?
答案 0 :(得分:3)
你的问题是一样的;它不是lambda语法本身,而是你在匿名方法中关闭局部变量(你使用的delegate
语法是匿名方法的第一次迭代,它在.NET中首次亮相2.0)。
如果您想这样做,您将使用解决方法:
for (int i = 0; i < 5; i++)
{
int j = i;
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + j);
}))).Start();
}
请注意,这与您尝试(复制)的内容类似,但它需要在闭包的外和内部循环。在匿名函数中复制它(如在您的示例中)并没有帮助。
答案 1 :(得分:3)
你需要引入一个临时的:
for (int i = 0; i < 5; i++)
{
int temp = i; // Add this
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + temp);
}))).Start();
}
问题在于代理如何围绕代码中的外部变量i
,我的代理temp
。范围是错误的(在for循环之外),所以当线程开始时,i
已经增加了很多,如果不是全部的话。
对于你的第二个例子,你需要做同样的事情。只做临时工:
var temp1 = param1;
var temp2 = param2;
var temp3 = param3;
var temp4 = param4;
Thread t = new Thread(new ThreadStart(delgate()
{
threadLogic(temp1, temp2, temp3, temp4);
}));
t.Start();
// This is now safe, since the closure above is over "temp*"
param1 = param2 = param3 = param4 = null;