Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding Parallel.For Loop and local variables

I am new in the parallel computing and I'm with some problems running a Parallel.For in C#. I'm trying visit multiple Web Sites in simultaneous, get the HTML and register them in multiple SQLite Database. Everything seems work fine until I check the results more precisely. I noticed that in one loop for 0 to 20, the code entered 20 times in the shared part of loop and only 16 times in local part. So, was missing 4 results. To understand the problem I made a experience where I only put two counters. One in the global part and another in the local. The output of global count was 20 and in the local part 1! After that I put a 2 seconds sleep before the returning of global part to the local part. In this case the output of global count was 20 and in the local part was 13! Can you explain me what I'm doing wrong?

static void ParalellCalc()
{
    var tm = new Stopwatch();
    tm.Start();
    int count = 0;
    int count2 = 0;
    var parl = Parallel.For<int>(0, 20,
        new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount},
        () => 0, (i, state, Enrada) =>
    {
        count++;
        Thread.Sleep(2000);
        return Enrada;
    },
    (x) =>
    {
        count2++;
    });

    tm.Stop();
    Console.WriteLine(tm.Elapsed);
    Console.WriteLine("Global: " + count.ToString());
    Console.WriteLine("Local: " + count2.ToString());
    Console.WriteLine(tm.Elapsed);
    tm.Reset();
}

EDIT: I go into your suggestions and I made the same example with the Interlocked.Increment to increment the counters. The produced results are exactly the same. If I remove the Thread.Sleep(2000) the second counter produce the result of 1!? If I don't remove produce the result of 16. The first counter display in all the cases the value of 20 as should be. Anyone can explain that?

static void ParalellCalc()
{
    var tm = new Stopwatch();
    tm.Start();
    int count = 0;
    int count2 = 0;
    var parl = Parallel.For<int>(0, 20,
        new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount},
        () => 0, (i, state, Enrada) =>
    {
        Interlocked.Increment(ref count);
        return Enrada;
    },
    (x) =>
    {
        Interlocked.Increment(ref count2);
    });

    tm.Stop();
    Console.WriteLine(tm.Elapsed);
    Console.WriteLine("Global: " + count.ToString());
    Console.WriteLine("Local: " + count2.ToString());
    Console.WriteLine(tm.Elapsed);
    tm.Reset();
}
like image 215
Marco Teixeira Avatar asked Dec 06 '25 05:12

Marco Teixeira


1 Answers

++ operator is not thread safe, because it's not atomic. Interlocked.Increment is thread safe. Interlocked.Increment(ref count) instead of count++ and the same for count2 would probably fix the counting.

like image 131
Renat Avatar answered Dec 08 '25 19:12

Renat



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!