3

I am trying to iterate through a 2D array and then add to parts of another 2D array in a Parallel.For loop. I have found examples where an accumulation is being done inside the loop on a single variable but am not sure what to do here. GridB is doing accumulation so surely it needs to be locked as items in it could be added to from different threads If it needs to be locked how do you go about locking an entire array like this?

int[,] GridA = new int[D + 2, D + 2];
int[,] GridB = new int[D + 2, D + 2];

Parallel.For(1, D+1 , r =>
{
for (int c = 1; c <= D ; c++)
    if (GridA[r, c] != 0)
    {
        int v = GridA[r, c];

        GridB[r - 1, c - 1] += v;
        GridB[r - 1, c] += v;
        GridB[r - 1, c + 1] += v;

        GridB[r, c - 1] += v;
        GridB[r, c + 1] += v;

        GridB[r + 1, c - 1] += v;
        GridB[r + 1, c] += v;
        GridB[r + 1, c + 1] += v;
    }
});
4
  • It'd be easier if you used jagged array [][] instead of a two dimensional array [,]. Commented Jun 3, 2013 at 1:03
  • 1
    What is the advantage of a jagged array in this case? Commented Jun 3, 2013 at 1:05
  • As long as the threads don't access the same elements in the array, you can do this without locking. Commented Jun 3, 2013 at 2:02
  • @user2425056 You could lock the three relevant rows in GridB, which would pretty much secure the threading, while still allowing them to switch properly. Commented Jun 3, 2013 at 4:17

1 Answer 1

1

You could just lock GridB like so:

Parallel.For(1, D+1 , r =>
{
  for (int c = 1; c <= D ; c++)
  {
    if (GridA[r, c] != 0)
    {
      int v = GridA[r, c];
      lock(GridB) 
      { 
        GridB[r - 1, c - 1] += v;
        // etc.
      }
    }
  }
});

However, you are serializing all access to GridB which sort of defeats the purpose of using multiple threads.

If all you want to do is add a fixed value to each element, Interlocked.Add in the System.Threading namespace will do the add atomically, so you don't need to take out a lock on the whole array.

Here's a sample of the usage:

Parallel.For(1, D+1 , r =>
{
    for (int c = 1; c <= D ; c++)
      if (GridA[r, c] != 0)
      {
         int v = GridA[r, c];

          Interlocked.Add(ref GridB[r - 1, c - 1], v);
          // rinse, repeat
      }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. This is working. At least the algorithm is running about 2x faster. Will still have to check for accuracy against the serial version.
@Yorye, I have changed the algorithm to use jagged arrays and the speedup is noticeable. While this was not the answer to my question it lead me to a fruitful discovery. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.