C#Threadpool同步查询

时间:2009-08-20 15:07:48

标签: c# thread-safety

使用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()之后,我仍然得到一个空引用异常。

3 个答案:

答案 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。