我有以下情景,
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?我该如何解决这个问题。
答案 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)
)内分配,这不是线程安全的。您可以使用上面的建议而不是添加功能。