并行foreach会在其中创建不同的函数副本

时间:2014-06-26 12:27:13

标签: c#

我有以下情景,

Parallel.Foreach(al , sentence =>
{
  function abc
   {
      double x;
   }
   y = Add(ref y, x)
}

 public static double Add(ref double location1, double value)
        {
            double newCurrentValue = 0;
            while (true)
            {
                double currentValue = newCurrentValue;
                double newValue = currentValue + value;
                newCurrentValue = Interlocked.CompareExchange(ref location1, newValue, currentValue);
                if (newCurrentValue == currentValue)
                    return newValue;
            }
        }

对于句子数组中的每个句子,有一些将被计算的x值。我想把所有句子的这些值总结为变量y。但是当我每次获得不同的y值时运行代码。我猜它是因为x在写入y之前被覆盖了。那么对于每个句子是Parallel Foreach创建不同或相同的函数abc?我该如何解决这个问题。

3 个答案:

答案 0 :(得分:2)

由于多个线程同时访问y进行写入

例如,下面的代码可能不会导致4950

int y=0;
Parallel.ForEach(Enumerable.Range(0, 100), x => y += x);

但是这个确保了它

 int z = 0;
 Parallel.ForEach(Enumerable.Range(0, 100), x => Interlocked.Add(ref z, x));

答案 1 :(得分:0)

那是因为y= y+x;不是线程安全的。请改用Interlocked.Add

Interlocked.Add(ref y, x);

答案 2 :(得分:0)

如上所述,求和/分配本身并不是线程安全的。但是Interlocked.Add不能用于双打。这将留下锁定选项,但是,使用伪代码有一种更简单的方法:

var y= al.AsParallel().Select(sentence => function(sentence )).Sum();

这使用线程安全的double Sum(this ParallelQuery<double> source)

修改的 在您发布的更新代码中,y仍然在多个线程(y = Add(ref y, x))内分配,这不是线程安全的。您可以使用上面的建议而不是添加功能。