Search code examples
c#nullreferenceexceptionmanualresetevent

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


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);`     

Solution

  • 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.