0
using System.Threading.Tasks;

const int _Total = 1000000;
[ThreadStatic]
static long count = 0;

static void Main(string[] args)
{
    Parallel.For(0, _Total, (i) =>
    {
        count++;
    });

    Console.WriteLine(count);
}

I get different result every time, can anybody help me and tell me why?

Himanshu
  • 31,810
  • 31
  • 111
  • 133
Scarface
  • 89
  • 5

2 Answers2

2

Most likely your "count" variable isn't atomic in any form, so you are getting concurrent modifications that aren't synchronized. Thus, the following sequence of events is possible:

  • Thread 1 reads "count"
  • Thread 2 reads "count"
  • Thread 1 stores value+1
  • Thread 2 stores value+1

Thus, the "for" loop has done 2 iterations, but the value has only increased by 1. As thread ordering is "random", so will be the result.

Things can get a lot worse, of course:

  • Thread 1 reads count
  • Thread 2 increases count 100 times
  • Thread 1 stores value+1

In that case, all those 100 increases done by thread 2 are undone. Although that can really only happen if the "++" is actually split into at least 2 machine instructions, so it can be interrupted in the middle of the operation. In the one-instruction case, you're only dealing with interleaved hardware threads.

Christian Stieber
  • 9,954
  • 24
  • 23
  • thanks your answer!it's useful! i konw my "count" is not atomic,so i use [ThreadStatic] attribute.MSDN said that "Indicates that the value of a static field is unique for each thread." Parallel.For() it works by so many threads,but in each thread static field can be unique.so [ThreadStatic] is not right.I must remove [ThreadStatic],and add "lock" or some synchronized things.Am i right? – Scarface Oct 06 '12 at 09:55
  • Eh, yes. I didn't actually realize what the "ThreadStatic" meant, maybe even considered it a comment. Either way, if you make this "thread static", the result is similar, although for different reasons: each thread will have its own "count", so at the end you're only getting the count from one thread. And yes, "lock" sounds better, as do words like "atomic" or "synchronized" or whatever the language uses. In your simple loop you won't be seeing any improvement by the parallel for, since your loop body can't run in parallel at all. You're actually just adding overhead :-) – Christian Stieber Oct 06 '12 at 12:55
  • Yes,you are right.In the simple loop i don't improvement by the parallel for,just adding overhead.Thanks for you help.This code are real parallel: Parallel.For(1,100,(i)=>{ arr[i] = i; }). – Scarface Oct 06 '12 at 17:15
1

It's a typical race condition scenario.

So, most likely, ThreadStatic is not working here. In this concrete sample use System.Threading.Interlocked:

void Main()
{
    int total = 1000000;
    int count = 0;

    System.Threading.Tasks.Parallel.For(0, _Total, (i) =>
    {
    System.Threading.Interlocked.Increment(ref count);      
    });

    Console.WriteLine(count);
}

Similar question C# ThreadStatic + volatile members not working as expected

Community
  • 1
  • 1
Regfor
  • 8,515
  • 1
  • 38
  • 51