-3

I have following scenario ,

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

for each sentence in array of sentence al there is some value of x that will be calculated. And I want to sum up these values of all sentences in to variable y. But when I run code each time I get different value of y. And I guess its because x is getting overwritten before writing into y. So for each sentence is Parallel Foreach creating different or same copy of function abc? How can I fix this.

3 Answers3

2

Since multiple threads access to y for writing at the same time

For ex, below code may not result in 4950

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

but this one ensures it

 int z = 0;
 Parallel.ForEach(Enumerable.Range(0, 100), x => Interlocked.Add(ref z, x));
I4V
  • 34,891
  • 6
  • 67
  • 79
0

That's because y= y+x; is not thread-safe. Use Interlocked.Add instead

Interlocked.Add(ref y, x);
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • I tried that now, see edited code, still same. I think value of x is getting overwritten before it writes to y. – user3667737 Jun 26 '14 at 12:46
  • @user3667737 The code you posted is not what I suggested, and is not thread-safe at all. Replace this line `y = Add(ref y, x)` with what I posted, and delete your `Add` method. – dcastro Jun 26 '14 at 13:26
  • @user3667737 Oh yeah, you're right. Ok, then change your `Add` method to return `void`, and call it like this `Add(ref y, x)`, instead of this `y = Add(ref y, x)`. That should make the operation atomic. – dcastro Jun 26 '14 at 13:37
0

As mentioned, summing/assigning by itself isn't thread safe. However Interlocked.Add can't be used for doubles. That would leave the option for locking, however, there is an easier way, using your pseudo code:

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

This uses the double Sum(this ParallelQuery<double> source) which is thread safe

edit In the updated code you've posted, y is still assigned inside multiple threads (y = Add(ref y, x) ), which is't thread safe. Instead of the add function you could use the suggestion above.

Me.Name
  • 12,259
  • 3
  • 31
  • 48