Parallel.For(): Update variable outside of loop

Solution 1:

You can't do this. sum is being shared across you parallel threads. You need to make sure that the sum variable is only being accessed by one thread at a time:

// DON'T DO THIS!
Parallel.For(0, data.Count, i =>
{
    Interlocked.Add(ref sum, data[i]);
});

BUT... This is an anti-pattern because you've effectively serialised the loop because each thread will lock on the Interlocked.Add.

What you need to do is add sub totals and merge them at the end like this:

Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
    {
        subtotal += result[i];
        return subtotal;
    },
    (x) => Interlocked.Add(ref sum, x)
);

You can find further discussion of this on MSDN: http://msdn.microsoft.com/en-us/library/dd460703.aspx

PLUG: You can find more on this in Chapter 2 on A Guide to Parallel Programming

The following is also definitely worth a read...

Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4 - Stephen Toub

Solution 2:

sum += y; is actually sum = sum + y;. You are getting incorrect results because of the following race condition:

  1. Thread1 reads sum
  2. Thread2 reads sum
  3. Thread1 calculates sum+y1, and stores the result in sum
  4. Thread2 calculates sum+y2, and stores the result in sum

sum is now equal to sum+y2, instead of sum+y1+y2.

Solution 3:

Your surmise is correct.

When you write sum += y, the runtime does the following:

  1. Read the field onto the stack
  2. Add y to the stack
  3. Write the result back to the field

If two threads read the field at the same time, the change made by the first thread will be overwritten by the second thread.

You need to use Interlocked.Add, which performs the addition as a single atomic operation.

Solution 4:

Incrementing a long isn't an atomic operation.