2009-08-20 85 views
1

我使用threadpool类和一个ManualResetEvents数组遇到了一些困难。下面是我正在做的一个简单的例子。问题是,在DoWork方法中,我得到了对resetEvent [param as int]对象的空引用。C#线程池同步查询

似乎无法确定我做错了什么。

(编辑:得到了代码块的工作)

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

我已经做了多次编辑,以获得代码块的工作。如果有人看到前面的迭代,请原谅它的混乱。 – Setheron 2009-08-20 15:12:04

+0

我也尝试过锁定每个.Set()调用,因为这会导致对该对象进行易失性读/写操作,但似乎不起作用。 非常令人沮丧。 – Setheron 2009-08-20 15:59:42

+0

为什么在'Set()'之后你会发出内存障碍*?你需要在你调用Set()之前看到更新的数组元素*! – 2009-08-21 15:03:42

回答

0

差不多,我发现这个问题是

for (int i = 0; i < NumThreads ; i++)  
{   
resetEvents[i] = new ManualResetEvent(false);   
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]);  
} 

而是宣布了新的ManualResetEvent我简单地称为复位()。这个问题似乎是,虽然我会使用MemoryBarrier或锁,物理内存不会更新,所以它会指向空。

2

您不能使用as关键字将其转换为int(因为int不是引用类型)。使用(int)param代替:

private void DoWork(object param) 
{ 
    //do some random work 
    resetEvents[(int)param].Set(); 
} 

另一种方法,我觉得更清洁是将等待句柄传递给替代方法:

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(); 
} 

这样的辅助方法没有关于等待句柄是怎么认识在外面管理;而且它也无法到达其他线程的等待句柄。

+0

我刚写了一个简单的例子。我不是说它是100%syntatically正确的,但我会修正的例子 – Setheron 2009-08-20 15:14:46

+0

不认为你的意思是使用param作为索引器....应该能够做 (参数为ManualResetEvent).Set (); – CSharpAtl 2009-08-20 15:24:51

+0

@CSharpAtl:是的,我注意到了。我的代码死了复制/粘贴死亡,我猜; o) – 2009-08-20 15:26:49

1

volatile ManualResetEvent[]并不意味着访问数组元素遵循易失性语义。只有访问保存对数组引用的变量才会变得不稳定。尝试在分配数组元素后插入内存屏障,或使用Thread.VolatileWrite来设置它们,例如

Thread.VolatileWrite (ref resetEvents[i], new ManualResetEvent (false)) ; 
+0

哦。我认为给数组赋值会导致成员窃取关键字。 我不熟悉你提到的其他两种方式(内存屏障和Interlocked.Exchange) – Setheron 2009-08-20 15:28:47

+0

实际上,Interlocked.Xxx在这里并不是一个好主意,因为你不需要读取和更新数据。 – 2009-08-20 16:48:57