使用Dispatcher.BeginInvoke()时如何避免竞争条件?

时间:2014-09-18 02:51:03

标签: c# async-await

以下代码只记录a和b之间的素数。 c#async await适用于我的代码,但较旧的dispatcher方式会产生奇怪的结果。当我点击按钮时,我得到以下结果:
70435素数在2000000和2999999之间 67883素数在3000000和3999999之间 66330素数在4000000和4999999之间 65367素数在5000000和5999999之间 这是i should be <5 and begin with 1000000以来的错误。有人帮忙解释这里的竞争状况吗?

private void _button_Click(object sender, RoutedEventArgs e)
{
    //Go();
    Task.Run(() => Go1());
}
void Go1()
{
    Dispatcher.BeginInvoke(new Action(() => _button.IsEnabled = false));
    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));

}
int GetPrimesCount(int start, int count)
{
    return ParallelEnumerable.Range(start, count).Count(n =>
    Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0));
}

1 个答案:

答案 0 :(得分:7)

这是一个古老的问题:lambdas靠近变量,而不是,因此多次更新访问的i实际上是相同的i Dispatcher 1}}。

在旁注中,我个人会重写代码,根本不使用Dispatcher。总是有一个比private async void _button_Click(object sender, RoutedEventArgs e) { _button.IsEnabled = false; var progress = new Progress<Tupe<int, int>>(update => { _results.Text += update.Item1 + " primes between " + (update.Item2 * 1000000) + " and " + ((update.Item2 + 1) * 1000000 - 1) + Environment.NewLine)); }); await Task.Run(() => Go1(progress)); _button.IsEnabled = true; } void Go1(IProgress<Tuple<int, int>> progress) { for (int i = 1; i < 5; i++) { int result = GetPrimesCount(i * 1000000, 1000000); if (progress != null) progress.Report(Tuple.Create(result, i)); } } 更好的解决方案:

{{1}}