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