ManualResetEvent 抛出 NullReferenceException:对象引用未设置为对象的实例
ManualResetEvent throws NullReferenceException: Object reference not set to an instance of an object
代码抛出
NullReferenceException: Object reference not set to an instance of an object
在线((ManualResetEvent)handles[i]).Set()
。我在调试时检查了 handles[i] 是否有值。我做错了什么?
` 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);`
发生的事情是你在 i
上使用了 a modified closure,它在线程内部使用。
i
的值在 在 用于 ((ManualResetEvent)handles[i]).Set();
之前递增,此时您还没有设置 handles[i]
.
发生这种情况是因为调用线程在新线程执行 ((ManualResetEvent)handles[i]).Set();
之前立即继续执行下一行代码 i++;
。这是一个经典的竞争条件。
要解决此问题,请在启动线程之前添加以下行:
int j = i;
然后在((ManualResetEvent)handles[i]).Set();
中使用j
代替i
:
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++;
}
当然,当您 运行 调试器下的代码时,线程已完全改变,因此您没有发现问题。
代码抛出
NullReferenceException: Object reference not set to an instance of an object
在线((ManualResetEvent)handles[i]).Set()
。我在调试时检查了 handles[i] 是否有值。我做错了什么?
` 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);`
发生的事情是你在 i
上使用了 a modified closure,它在线程内部使用。
i
的值在 在 用于 ((ManualResetEvent)handles[i]).Set();
之前递增,此时您还没有设置 handles[i]
.
发生这种情况是因为调用线程在新线程执行 ((ManualResetEvent)handles[i]).Set();
之前立即继续执行下一行代码 i++;
。这是一个经典的竞争条件。
要解决此问题,请在启动线程之前添加以下行:
int j = i;
然后在((ManualResetEvent)handles[i]).Set();
中使用j
代替i
:
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++;
}
当然,当您 运行 调试器下的代码时,线程已完全改变,因此您没有发现问题。