0

The code throws

NullReferenceException: Object reference not set to an instance of an object

on the line ((ManualResetEvent)handles[i]).Set(). I checked handles[i] has a value when I debug it. What am I doing wrong?

`               string[] fileEntries = Directory.GetFiles(pathFife);
                ManualResetEvent[] handles = new ManualResetEvent[fileEntries.Count()];
                int i = 0;
                foreach (string fullName in fileEntries)
                {
                    handles[i] = new ManualResetEvent(false);
                        var thread = new Thread(() =>
                            {
                                AddFile(fullName, month, year, user);
                                ((ManualResetEvent)handles[i]).Set();
                            });
                        thread.Start();
                    i++;
                }
                WaitHandle.WaitAll(handles);`     

1 Answers1

0

What's happening is you have a modified closure on i where it's used inside the thread.

The value of i is being incremented before it is used in ((ManualResetEvent)handles[i]).Set();, and at that point you haven't set the value of handles[i].

This happens because the calling thread immediately goes on to the next line of code, i++;, before the new thread has executed ((ManualResetEvent)handles[i]).Set();. It's a classic race condition.

To fix this problem, add the following line just before you start the thread:

int j = i;

And then use j instead of i in ((ManualResetEvent)handles[i]).Set();:

foreach (string fullName in fileEntries)
{
    handles[i] = new ManualResetEvent(false);
    int j = i;
    var thread = new Thread(() =>
    {
        AddFile(fullName, month, year, user);
        ((ManualResetEvent)handles[j]).Set();
    });
    thread.Start();
    i++;
}

Of course, when you run the code under the debugger the threading is completely altered and thus you didn't see the problem.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276