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



下面的代码只记录a和b之间的素数的数量。c#async await适用于我的代码,但旧的dispatcher方式会产生奇怪的结果。当我单击按钮时,我得到了以下结果:
70435个素数介于2000000和2999999之间
67883个素数介于3000000和39999999之间
66330个素数介于4000000和4999999之间
65367个素数介于5000000和5999999之间
这是错误的,因为CCD_。有人帮忙解释一下这里的比赛情况吗?

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));
}

这是一个老问题:lambdas关闭变量,而不是。因此,多个更新访问的i实际上是相同的i

顺便说一句,我会亲自重写代码,完全不使用Dispatcher。总有比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));
  }
}

最新更新