スレッドスレッドプールにすべてのバックグラウンドが終了したときに通知されます
-
21-08-2019 - |
質問
私はシナリオを持っています。 各スレッドは、その仕事をしていませんし、ThreadPoolのに戻ります。 すべてのバックグラウンドスレッドが終了したら、メインスレッドに通知することも可能なオプションは何ですか?
現在、私が作成したスレッドのそれぞれについて、変数をインクリメントし、バックグラウンドスレッドが終了する程度であるとき、それをデクリメントと自家製のメソッドを使用しています。 これはうまく動作しますが、より良いオプションがある場合、私は興味があった。
解決
(スレッド間)の変数をデクリメント(それがゼロになる、すなわち時)イベントを発生させInterlocked.Decrement
で行われていない限り、少し危険ですが、あなたは最後のスレッドを持っている場合、そのアプローチは問題ないはずです。 (プラスあなたがプロセスを殺すためにしたくない)、それは例外の場合には、それを失うことを避けるために、「ついに」ブロックでなければならないであろうことに注意してください。
「パラレル拡張機能」(または.NET 4.0を使用)では、あなたもここParallel.ForEach
オプション...ブロックとして行われ、すべてを取得する別の方法かもしれないで見えるかもしれません。手動でそれらをすべて見ることがなくなります。
他のヒント
これを試してみてください: https://bitbucket.org/nevdelap/poolguardする
using (var poolGuard = new PoolGuard())
{
for (int i = 0; i < ...
{
ThreadPool.QueueUserWorkItem(ChildThread, poolGuard);
}
// Do stuff.
poolGuard.WaitOne();
// Do stuff that required the child threads to have ended.
void ChildThread(object state)
{
var poolGuard = state as PoolGuard;
if (poolGuard.TryEnter())
{
try
{
// Do stuff.
}
finally
{
poolGuard.Exit();
}
}
}
複数PoolGuardsは、スレッドが終了し、プールが既に閉じられたときに開始されていないスレッドを処理している際に追跡するためにさまざまな方法で使用することができます。
、あなたはこのようにWaitHandle.WaitAllメソッドを使用することができます:
List<WaitHandle> events = new List<WaitHandle>();
for (int i = 0; i < 64; i++)
{
ManualResetEvent mre = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(
delegate(object o)
{
Thread.Sleep(TimeSpan.FromMinutes(1));
((ManualResetEvent)o).Set();
},mre);
events.Add(mre);
}
WaitHandle.WaitAll(events.ToArray());
実行はすべてManualResetEventsが設定されているまで、あるいは、あなたがWAITANYメソッドを使用してお待ちしております。
WAITANYとWaitAllメソッドは、実行をブロックしますが、あなたは、単にリスト、またはスレッドがけれども行われている場合は、後で決定するために産卵されたタスクにリンクManualResetEventsの辞書を使用することができます。
現時点でこれを行うには、組み込みの方法はありませんだ - 私はそれプールスレッドの使用に関する最大の痛みの一つ見つける
。マークが、これはパラレル拡張機能/ .NET 4.0で固定されているものの一種である、言うように。
あなたは各スレッドに個別のManualResetEventを与え、行われたときに、各イベントを設定していませんでした。そして、メインスレッドであなたが渡されたすべてのイベントを待つことができます。
マルクのソリューションが最適です。
あなたはジョブを起動するためにいくつかのスレッドを望んでいた場合は、通知を受信するためにいくつかの他のスレッドは、WaitHandleを使用することができます。コードははるかに長いです。
int length = 10;
ManualResetEvent[] waits = new ManualResetEvent[length];
for ( int i = 0; i < length; i++ ) {
waits[i] = new ManualResetEvent( false );
ThreadPool.QueueUserWorkItem( (obj) => {
try {
} finally {
waits[i].Set();
}
} );
}
for ( int i = 0; i < length; i++ ) {
if ( !waits[i].WaitOne() )
break;
}
WAITONE方法は、書かれたとして、常にtrueを返しますが、私はあなたには、いくつかのオーバーロードは、引数としてタイムアウトを取ることを覚えておくにするためにそのように書かれています。
何セマフォを使用して、同じくらいあなたのスレッドプールとして、それに制限を設定について。セマフォを取得する方法を持っている、あなたは、あなたのスレッドを起動したときに、あなたのスレッドの終わりにそれを解放し、あなたはすべてのセマフォを取り上げてきた場合にはイベントを発生させるときに呼び出される。