2009-08-20 20 views
1

私は、スレッドプールクラスとManualResetEventsの配列を使用するのが少し難しかったです。以下は、私がやっていることの簡単な例です。問題は、DoWorkメソッドで、resetEvent [param as int]オブジェクトへのnull参照を取得していることです。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()の後でもまだnull参照例外が発生します。

+0

私は複数の編集を行って、コードブロックが機能するようにしました。誰かが以前の反復を見たなら、それが混乱していると言い訳してください。 – Setheron

+0

私はまた、すべての.Set()呼び出しをロックしようとしましたが、これはオブジェクトの揮発性の読み込み/書き込みを引き起こすはずですが、どちらも機能しないように見えるからです。 非常にイライラします。 – Setheron

+0

なぜあなたは 'Set()'の後にメモリバリア*を発行しますか?あなたは 'Set()'を呼び出す前に更新された配列要素*を見る必要があります! –

答えて

0

はかなり私は、問題が

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

の代わりに、私は単純にリセット(と呼ばれる新しいManualResetEventを宣言)にあった見つけました。問題は、MemoryBarrierまたはロックを使用しても、物理メモリはまだ更新されないため、nullを指すことになっていたようです。

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%統語的に正しいことを意味しませんでしたが、私は例を修正するでしょう – Setheron

+0

あなたはインデクサーとしてパラメタを使用するつもりはないと思っています....ちょうどできるようにする必要があります (ManualResetEventとしてparam).Set (); – CSharpAtl

+0

@CSharpAtl:はい、私はそれに気付きました。私のコードはコピー/ペーストの死によって死んだと思う; o) –

1

volatile ManualResetEvent[]は、の配列要素へのアクセスが揮発性セマンティクスに従うことを意味しません。配列への参照を保持する変数へのアクセスのみがvolatileです。配列要素を割り当てた後にメモリバリアを挿入するか、Thread.VolatileWriteを使用して配列を設定してみてください。

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

ああ。私は配列にvolatileを割り当てると、メンバーはキーワードを継承すると考えました。 あなたが言及した他の2つの方法(メモリバリアとInterlocked.Exchange)に精通していません – Setheron

+0

実際にInterlocked.Xxxはあなたのデータを読み書きする必要がないのでここではお勧めできません。 –

関連する問題