2011-06-28 10 views
3

私はスレッドプールを使って(驚くことではないが)スレッドセットを管理しています。WaitAllとdoneイベントのスレッド問題 - シグナル発射例外

ManualResetEvent[] doneEvents = new ManualResetEvent[char_set.Length]; 

public struct string_char 
    { 
     public string[] _str_char; 
     public ManualResetEvent _doneEvent; 

     public string_char(string[] str_char, ManualResetEvent doneEvent) 
     { 
      _str_char = str_char; 
      _doneEvent = doneEvent; 
     } 
    } 

私はcharの配列を作成し、ここでループを持っているし、私はchar型の配列および移入私の構造体のインスタンスを作成します。私は何をしようとしていることは行われたときに、私はそれらを知らせるために取得することです行われたイベント:だから

doneEvents[no_of_elements - 1] = new ManualResetEvent(false); 
      string_char s_c = new string_char(array_holder, doneEvents[no_of_elements - 1]); 
      ThreadPool.QueueUserWorkItem(ThreadPoolCallback, s_c); 

、スレッドが作成され、プールに追加し、それが行われたイベントセット完了したときには、陽気に消灯し、実行します:バックメインで

public void ThreadPoolCallback(Object s_c) 
{ 
string_char _s_c = (string_char)s_c; 
//do the calculations... 
//when done: 
_s_c._doneEvent.Set(); 
} 

をコードをループするeは、ここで待っている:

WaitHandle.WaitAll(doneEvents); 
Console.WriteLine("All calculations are complete."); 

トラブルを私は例外を取得しておくされます。

'WaitAll for multiple handles on a STA thread is not supported.' 

私はGoogleでこれを見てきましたが、それは本当に助けにはならない、私は間違って何をやっています。これは基本的にms msnという例の繰り返しです。私はクラスではなくstructを使用していますか?

メインのMTA(doh!)に切り替えることで、以下のアドバイスを使用して問題を解決しました。また、maxが64スレッド数であることを知ることは有用でした。だから私は最終的なアプリはそれよりもさらにいくつか実行されるように別の待機モデルに切り替える必要があります!学ぶたくさん。

ありがとうございました。

答えて

2

を、このようにWaitHandle.WaitAllを使用しての問題がいくつかあります。あなたはすでにそれらの1つを発見しました。もう1つは、64ハンドル制限があるためスケーラビリティがあまり高くありません。ここでは、複数の作業項目が完了するのを待つために使用するパターンです。それはCountdownEventクラスを使用します。

using (var finished = new CountdownEvent(1)) 
{ 
    foreach (var workItem in workItemCollection) 
    { 
    var captured = item; 
    finished.AddCount(); 
    ThreadPool.QueueUserWorkItem(
     (state) => 
     { 
     try 
     { 
      ProcessWorkItem(captured); 
     } 
     finally 
     { 
      finished.Signal(); 
     } 
     }, null); 
    } 
    finished.Signal(); 
    finished.Wait(); 
} 
+0

ありがとうございました。私は、スレッド数が64にしかならないことを私に知らせたのが好きです。ありがとう。 – flavour404

2

それはあなたのメイン()で、それはWaitAllはブロッキング・コールであるとして、あなたはSTAスレッドでWaitHandle.WaitAll()を使用することはできません[STAThread]ない[MTAThread]

で定義されているので、これは、メッセージポンプを防止するために行われています走るこれはWin32では許可されていないため、.NETでは許可されていません。限られた量のポンピングを行うWaitOneやThread.Joinのような他の同期プリミティブの1つを使用してください。

pulled from here

しかし、より良い選択は、あなたがやりたい新しいTaskを使用することです。 hereも同様の例です。

+0

ありがとうJalal、これは誰にもこれを与えるのは本当に難しい選択でした。 – flavour404

0

スレッドMTAをマークするか(STAでなければならないUIスレッドでない場合)、または別の待機メカニズムを使用します。たとえば、タスク数と、1つのウェイトハンドルを使用することができます。

int taskCount = 0; 

// Launch a thread 
Interlocked.Increment(ref taskCount); 

// A thread terminates 
if (Interlocked.Decrement(ref taskCount) == 0) 
    doneEvent.Set(); 
0

試してみてください。

foreach(ManualResetEvent doneEvent in doneEvents) 
      WaitHandle.WaitOne(doneEvent); 

    Console.WriteLine("All calculations are complete."); 
+0

この方法はデッドロックにつながります。 foreachのwaitループ中にdoneEventsをロックする必要があります。スレッドが起動され、waitハンドルを追加したときにdoneEventsをロックする必要があります。 –

関連する問題