3

这是来自 Joseph Albahari 的优秀 C# 5.0 in a Nutshell book

在他的一章中,他提到了这个代码块中的一个竞争条件。我的猜测是它的意思是不言而喻的,因为他没有费心指定它在哪里,但是多次运行代码我无法产生上述竞争条件

_button.Click += (sender, args) =>
{
   _button.IsEnabled = false;
   Task.Run (() => Go());
};

void Go()
{
    for (int i = 1; i < 5; i++)
    {
        int result = GetPrimesCount (i * 1000000, 1000000);
        Dispatcher.BeginInvoke (new Action (() =>
       _results.Text += result + " primes between " + (i*1000000) + " and " + 
                                   ((i+1)*1000000-1) + Environment.NewLine));
    }

    Dispatcher.BeginInvoke (new Action (() => _button.IsEnabled = true));
}
4

2 回答 2

3

我不同意@Serge 的回答。您甚至不需要多个线程来查看问题。尝试以原始形式运行您的代码并注意输出。对我来说,它是以下内容,有时是随机的(我固定了第一个值):

1000000 primes between 5000000 and 5999999
1000000 primes between 5000000 and 5999999
1000000 primes between 5000000 and 5999999
1000000 primes between 5000000 and 5999999

注意最后 2 个值。它们都是一样的,但它们应该依赖于i. 问题不在于操作不是原子的,因为 GUI 线程无论如何都会按顺序执行操作。

发生这种情况的原因是传递给的 lambda 函数在执行时BeginInvoke获取值i ,而不是在初始化时,因此它们都会在执行i时看到最后一个值。解决方案是像这样显式地将i参数作为参数传递给 lambda:

for (int i = 1; i < 5; i++)
{
    int result = 1000000;
    Dispatcher.BeginInvoke(new Action<int>(j =>
    results.Text += result + " primes between " + (j * 1000000) + " and " +
                              ((j + 1) * 1000000 - 1) + Environment.NewLine), i);
}
于 2012-09-23T07:26:06.110 回答
2

这条线不会被原子计算:

_results.Text += result + " primes between " + (i*1000000) + " and " + ((i+1)*1000000-1) + Environment.NewLine));

因此,从 5 个并发运行的线程执行它可能会产生不同的有趣结果。

于 2012-09-23T00:20:23.150 回答