Search code examples
c#arraysmultithreading.net-2.0

Multithreading Fill Array


on C# Net 2.0

Code works slightly slower then single threaded version. xDiff = 2100, yDiff = 2000; Almost 14 sec in single threaded, 16 sec in multithreaded (this code). Something must be wrong. I need to fill result array. Only one time writes data on node of array, no reads so it should be appropriate for multi threading.

double[,] result = new double[xDiff, yDiff];
int threadCount = Environment.ProcessorCount;
ManualResetEvent finished = new ManualResetEvent(false);
int perthread = xDiff / threadCount;
int left = xDiff % threadCount;
int toProcess = threadCount;
int s = 0;
int e = left;
for (int ii = 0; ii < threadCount; ii++)
{
  ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
    {
      for (int x = s; x < e; x++)
        for (int y = 0; y < yDiff; y++)
        {
          result[x, y] = DoWork((xStart + x), (yStart + y), p)
        }
      if (System.Threading.Interlocked.Decrement(ref toProcess) == 0) finished.Set();
    }), null);
  s = e;
  e += perthread;
}
finished.WaitOne();
return result;

xStart, yStart is double and p is a big class. DoWork function Only calls some functions of p but not writes/change any data on class.

Briefly result[x, y] = DoWork((xStart + x), (yStart + y), p); I need to fill array as fast as i can. How can i do it?


Solution

  • I think that the issue here is that the variables s and e are closures that are being modified outside the threads, so the threads are getting the wrong values and are using incorrect ranges.

    To see if this is the case, try adding a Console.WriteLine() or Trace.WriteLine() to print out the values of s and e inside the thread (after the call to QueueUserWorkItem()) to see if this is what's happening.

    To fix this, copy the modified closures into temporary variables and use those in the thread, like so:

    for (int ii = 0; ii < threadCount; ii++)
    {
        int ts = s; // Copy them outside the loop.
        int te = e;
        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state)
        {
            for (int x = ts; x < te; x++) // Use the copy here.
    

    Also see Access to Modified Closure