使用threadpool类和ManualResetEvents数组时遇到了一些困难。下面是我正在做的一个简单的例子。问题是在DoWork方法中我得到了对resetEvent [param as int]对象的空引用。
似乎无法弄清楚我做错了什么。
(编辑:让代码块工作)
private static volatile ManualResetEvent[] resetEvents = new ManualResetEvent[NumThreads];
public void UpdateServerData()
{
for (int i = 0; i < NumThreads ; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object) i);
}
WaitHandle.WaitAll(resetEvents);
}
private void DoWork(object param)
{
//do some random work
resetEvents[(int)param].Set();
}
编辑:我试过插入一个System.Threading.Thread.MemoryBarrier();在每个.Set()之后,我仍然得到一个空引用异常。
答案 0 :(得分:2)
您无法使用as
关键字转换为int(因为int
不是引用类型)。请改用(int)param
:
private void DoWork(object param)
{
//do some random work
resetEvents[(int)param].Set();
}
我觉得更清晰的另一种方法是将wait句柄传递给方法:
public void UpdateServerData()
{
for (int i = 0; i < NumThreads ; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]);
}
WaitHandle.WaitAll(resetEvents);
}
private void DoWork(object param)
{
//do some random work
(param as ManualResetEvent).Set();
}
这样,worker方法不知道如何在外部管理等待句柄;并且它也无法错误地到达其他线程的等待句柄。
答案 1 :(得分:1)
volatile ManualResetEvent[]
并不意味着对数组元素的访问遵循volatile语义。只有访问保存对数组引用的变量才是易失性的。尝试在分配数组元素后插入内存屏障,或使用Thread.VolatileWrite
进行设置,例如
Thread.VolatileWrite (ref resetEvents[i], new ManualResetEvent (false)) ;
答案 2 :(得分:0)
我发现问题几乎在
for (int i = 0; i < NumThreads ; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]);
}
我没有声明一个新的ManualResetEvent,而是简单地调用了Reset()。问题似乎是虽然我会使用MemoryBarrier或锁,但物理内存还不会更新,所以它会指向null。