2009-08-20 89 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