ahmetsarias
ahmetsarias

Reputation: 251

Parallel.For does not wait all iterations

I am building an optimization program using Genetic Algorithms. I used Parallel.For in order to decrease time. But it caused a problem which is same in code below:

class Program
    {
        static void Main(string[] args)
        {
            int j=0;
            Parallel.For(0, 10000000, i =>
                {
                    j++;
                });
            Console.WriteLine(j);
            Console.ReadKey();
        }
    } 

Every time i run the program above, it writes a different value of j between 0 and 10000000. I guess it doesn't wait for all iterations to finish. And it passes to next line. How am i supposed to solve this problem? Any help will be appreciated. Thanks.

Edition: Interlocked.Increment(ref j); clause solves the unexpected results, but this operation causes about 10 times much more time when i compare with normal for loop.

Upvotes: 0

Views: 1396

Answers (3)

Theodoros Chatzigiannakis
Theodoros Chatzigiannakis

Reputation: 29213

Parallel.For does wait for all iterations to finish. The reason you're seeing unexpected values in your variable is different - and it is expected.

Basically, Parallel.For dispatches the iterations to multiple threads (as you would expect). However, multiple threads can't share the same writeable memory without some kind of guarding mechanism - if they do, you'll have a data race and the result is logically undeterministic. This is applicable in all programming languages and it is the fundamental caveat of multithreading.

There are many kinds of guards you can put in place, depending on your use case. The fundamental way they work is through atomic operations, which are accessible to you through the Interlocked helper class. Higher-level guards include the Monitor class, the related lock language construct and classes like ReaderWriterLock (and its siblings).

Upvotes: 3

grabthefish
grabthefish

Reputation: 918

You could use the Interlocked.Increment(int32) method which would probably be easiest.

Using Parallel.For will create multiple threads which will execute the same lambda expression; in this case all it does is j++.

j++ will be compiled to something like this j = j + 1, which is a read and write operation. This can cause unwanted behavior.

Say that j = 50.

Thread 1 is executing the read for j++ which will get 50 and will add 1 to it. Before that thread could finish the write operation to j another thread does the read operation and reads 50 from j then the first thread has finished his write operation to j making it 51 but the second thread still has 50 in memory as the value for j and will add 1 to that and again write 51 back to j.

Using the Interlocked class makes sure that every operation happens atomically.

Upvotes: 5

nvoigt
nvoigt

Reputation: 77304

Your access to j is not syncronized. Please read a basic book or tutorial on multi-threading and syncronization.

Parallel.For does wait for all iterations.

Using syncronization (and thereby defeating the use of the parallel for):

class Program
{
    static void Main(string[] args)
    {
        object sync = new object;
        int j=0;
        Parallel.For(0, 10000000, i =>
            {
                lock(sync)
                {
                  j++;
                }
            });
        Console.WriteLine(j);
        Console.ReadKey();
    }
} 

Upvotes: 3

Related Questions