0

I am trying to use a Parallel.for loop to speed up my process. I have not been able to make this work, because the indices that I used ran out of bounds. After researching the site, I think I know what I am doing wrong, and I thought that I found the solution too in the form of temporary variables that store the loop variables before entering the action in the code. Yet, this does not work in my example. I have found the link that somebody provided to System.Collections.Concurrent, which supposedly provides safe threading for situations like these, yet I do not know how to use that collection. How do I go about this?

I have tried to create a copy-paste code for you guys to run, but I do something wrong there which probably indicates my inexperience:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Text;

    namespace empty
    {
        class Program
        {
            double[, , ,] info = new double[100, 100, 10, 5];

            void calculate()
            {
                int row;
                int layer, tex_class;
                double result;
                try
                {
                    for (row = 0; row < 100; row++)
                    {
                        Parallel.For(0, 99, col =>
                        {
                            int tempcol = col;
                            for (layer = 0; layer < 10; layer++)
                            {
                                int templayer = layer;
                                for (tex_class = 0; tex_class < 5; tex_class++)
                                {
                                    int tempclass = tex_class;
                                    result = info[row, tempcol, templayer, tempclass];
                                }
                                //other code
                            }
                        });
                    }
                }
                catch { }
            }

            static void Main(string[] args)
            {
                calculate();
            }
        }
    }
Community
  • 1
  • 1

2 Answers2

1

because the loop is run in parallel, the variables layer and tex_class will be increased in different threads. This will result in a value that will exceed the in indices eventually. Make sure the scope of these variables is only inside the loop where variable is used. Decrease the scope as much as possible to avoid other threads increasing the same variable. This code worked for me:

class Program
{
    double[, , ,] info = new double[100, 100, 10, 5];

    public void calculate()
    {
        int row;
        double result;
        try
        {
            for (row = 0; row < 100; row++)
            {
                Parallel.For(0, 99, col =>
                {
                    for (int layer = 0; layer < 10; layer++)
                    {
                        for (int tex_class = 0; tex_class < 5; tex_class++)
                        {
                            result = info[row, col, layer, tex_class];
                        }
                        //other code
                    }
                });
            }
        }
        catch { }
    }
}

Besides that i'd recommend using the parallel for on the most outer loop to parallize as much work as possible. Initializing a parallel for creates overhead which might decrease your performance rather than increasing it. This is what i'd do here:

   class Program
    {
        double[, , ,] info = new double[100, 100, 10, 5];

        public void calculate()
        {
            double result;
            try
            {
                Parallel.For(0, 100, row =>
                {
                    for (int col = 0; col < 100; col++)
                    {
                        for (int layer = 0; layer < 10; layer++)
                        {
                            for (int tex_class = 0; tex_class < 5; tex_class++)
                            {
                                result = info[row, col, layer, tex_class];
                            }
                            //other code
                        }
                    }
                });
            }
            catch { }
        }
    } 
imjoris
  • 301
  • 1
  • 5
0

I think, you should use local loop variables, because your global layer variable is increased in all of the parallel threads, as is your tex_class variable.

Something like that:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text;

namespace empty 
{
    class Program
    {
        double[, , ,] info = new double[100, 100, 10, 5];

        void calculate()
        {
            try
            {
                for (int row = 0; row < 100; row++)
                {
                    Parallel.For(0, 99, col =>
                    {
                        double result;
                        int tempcol = col;
                        for (int layer = 0; layer < 10; layer++)
                        {
                            int templayer = layer;
                            for (int tex_class = 0; tex_class < 5; tex_class++)
                            {
                                int tempclass = tex_class;
                                result = info[row, tempcol, templayer, tempclass];
                            }
                            //other code
                        }
                    });
                }
            }
            catch { }
        }

        static void Main(string[] args)
        {
            calculate();
        }
    }
}

The rule of the thumb should be, your local variables should be local to the scope inside parallel for, or be protected by some sort of synchronization, or they will be accessed by several threads at once, leading to an unpredictable behavior.

Kaerber
  • 1,623
  • 16
  • 21