线程启动的竞争条件
此处提出了类似的问题,但答案通常似乎都与 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
或类似的事情,这让我相信,它不是传递值 if i,而是传递引用。 (这很奇怪,因为 int 是一种值类型)。
做这样的事情:
for (int i = 0; i < 5; i++)
(new Thread(new ThreadStart(delegate()
{
int j = i;
Console.WriteLine("Thread " + j);
}))).Start();
也没有帮助,即使我们已经复制了 i.我假设原因是它没有及时复制 i 。
做这样的事情:
for (int i = 0; i < 5; i++)
{
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + i);
}))).Start();
Thread.Sleep(50);
}
似乎可以解决问题,但是这是非常不可取的,因为我们在每次迭代上浪费了 50 毫秒,更不用说如果计算机负载很重,那么 50 毫秒可能还不够。
这是我当前的具体问题的示例:
Thread t = new Thread(new ThreadStart(delgate()
{
threadLogic(param1, param2, param3, param4);
}));
t.Start();
param1 = param2 = param3 = param4 = null;
with:
void threadLogic(object param1, object param2, object param3, object param4)
{
// Do some stuff here...
}
我希望 threadLogic() 在其自己的线程中运行,但是上面的代码给出了空引用异常。我认为这是因为在线程有机会启动之前这些值被设置为 null。
同样,放置 Thread.Sleep(100) 是可行的,但从各个方面来看这都是一个糟糕的解决方案。 对于这种特殊类型的比赛条件,你们有什么建议?
A similar question was asked here, but the answers generally all seem to relate to the lambda notation. I get a similar result without the lambda so I thought I'd ask for some clarification:
Say I have something like this:
for (int i = 0; i < 5; i++)
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + i);
}))).Start();
One would expect the following output:
Thread 0
Thread 1
Thread 2
Thread 3
Thread 4
Now I realise that the threads aren't started in any particular order, so let's just assume that the above lines can come out in any order.
But that is not what happens.
What instead happens:
Thread 3
Thread 4
Thread 4
Thread 4
Thread 4
or something similar, which leads me to believe that rather than passing the value if i, it is passing the reference. (Which is weird, since an int is a value type).
Doing something like this:
for (int i = 0; i < 5; i++)
(new Thread(new ThreadStart(delegate()
{
int j = i;
Console.WriteLine("Thread " + j);
}))).Start();
does not help either, even though we have made a copy of i. I am assuming the reason is that it hasn't made a copy of i in time.
Doing something like this:
for (int i = 0; i < 5; i++)
{
(new Thread(new ThreadStart(delegate()
{
Console.WriteLine("Thread " + i);
}))).Start();
Thread.Sleep(50);
}
seems to fix the problem, however it is extremely undesirable as we're wasting 50ms on each iteration, not to mention the fact that if the computer is heavily loaded then maybe 50ms may not be enough.
Here is a sample with my current, specific problem:
Thread t = new Thread(new ThreadStart(delgate()
{
threadLogic(param1, param2, param3, param4);
}));
t.Start();
param1 = param2 = param3 = param4 = null;
with:
void threadLogic(object param1, object param2, object param3, object param4)
{
// Do some stuff here...
}
I want threadLogic() to run in its own thread, however the above code gives a null reference exception. I assume this is because the values are set to null before the thread has had a chance to start.
Again, putting a Thread.Sleep(100) works, but it is an awful solution from every aspect.
What do you guys recommend for this particular type of race condition?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要引入一个临时变量:
问题在于委托如何关闭外部变量(您的代码中的
i
,我的代码中的temp
)。范围是错误的(在 for 循环之外),因此当线程启动时,i
已经增加了大部分(如果不是全部)。对于第二个示例,您需要执行相同的操作。只是做临时的:
You need to introduce a temporary:
The problem is in how delegates close around the outer variable (
i
in your code,temp
in mine). The scope is wrong (outside the for loop), so by the time the thread starts,i
has already been incremented most if not all of the way.For your second example, you need to do the same thing. Just make temporaries:
你的问题是一样的;这不是 lambda 语法本身,而是您在匿名方法中关闭局部变量的事实(您使用的
delegate
语法是匿名方法的第一次迭代,它首次亮相在 .NET 2.0 中)。如果您想这样做,您将需要使用一个解决方法:
请注意,这与您尝试的(复制)类似,但它需要位于闭包的外部和内部 循环。在匿名函数中复制它(就像在您的示例中一样)没有帮助。
Your issue is the same; it's not the lambda syntax itself, it's the fact that you're closing over a local variable in an anonymous method (the
delegate
syntax you're using was the first iteration of anonymous methods, which made its debut in .NET 2.0).If you want to do this, you'll have you use a workaround:
Note that this is similar to what you tried (copying), but it needs to be outside of the closure and inside the loop. Copying it within the anonymous function (like in your example) doesn't help.