3

基本的なスレッド化/並列処理を含む最初の Windows サービス プロジェクトに取り組んでいます。これまでのところかなり苦労しましたが、ゆっくりとスレッド化を理解し始めています (それについては後で説明します...)。

疎結合の 2 つのワーカー スレッドを含む Windows サービスがあります。スレッド A は FTP サーバーからファイルをダウンロードし、それらを解凍/準備して、スレッド B が FileSystemWatcher を監視する別のディレクトリに保存します。スレッド B はファイルを解析し、データを使ってさまざまなことを行い、いくつかの http 呼び出しを行い、最後にファイルをアーカイブして作業ディレクトリから削除します。

私は仕事を始めたばかりで、現在直面している問題は、スレッド A とスレッド B の両方が戻るのを待つ方法です。私はこの質問を見ました: タイムアウトのある複数のスレッドで Thread.Joinを見て、アイデアがありました。

問題は、x 個のスレッドがそれぞれ ax 秒のタイムアウトで戻るのを待っている場合、十分な数のスレッドがあると、通常の操作でもサービスが応答していないように見える可能性があることです (SCM が 30 秒と文句を言う前にタイムアウトを読みましたよね?)。さらに、スレッドをループするときに参加するまでの残り時間を追跡することでこの問題を解決すると、ワーカーのコレクションの最初でスレッドを待機する時間が長くなればなるほど、残りのスレッドが戻るまでの時間が短くなります。十分な数のスレッドがあると、予想される時間内にすべてのスレッドが戻ってきても、サービスは応答していないように見えます。

この場合、おそらく 14 秒のタイムアウトで A と B の両方を thread.join するだけです。これは、2 つのワーカーしかなく、両方を返すのに 14 秒で十分なように思われるためです。

可変数のワーカー スレッド (たとえば > 8) がある場合、このようなことを行う価値はありますか? これは確実に機能しますか?

注: 次のものは使用しないでください。複数のレベルで使用するのは悪い考えです。回答を見る

    protected override void OnStop()
    {
        // the service is stopping - set the event
        Worker.ThreadStopEvent.Set();

        // stop the threads
        Parallel.ForEach(_workerThreads, t =>
        {
            t.Join(new TimeSpan(0, 0, 28));
        });
    }
4

3 に答える 3

2

スレッドごとにタイムアウトを使用するのではなく、代わりにイベントを設定し、定期的Joinに短いタイムアウトで実行することをお勧めします。極端なバージョンは次のようになります。

Worker.ThreadStopEvent.Set();
Thread.Sleep(30000); // wait 30 seconds
// Now try to Join each thread, with a very short (20 ms, maybe) timeout.

このアプローチの最大の問題は、すべてのスレッドが 5 秒で停止した場合でも、常に 30 秒待機することです。

1秒間スリープしてからチェックを行うループを使用すると、よりうまくいく可能性があります。その後、停止したスレッドを追跡し、すべてのスレッドが停止したときにループを終了できます。

ただし、おそらくCountdownEventを使用するのが最善です。各スレッドは、停止時にシグナルを送信し、メイン スレッドはすべてのスレッドが停止するまで待機します。このWaitメソッドを使用すると、タイムアウト値を指定できます。Join待機後、非常に短いタイムアウトで呼び出すことにより、まだハングしているスレッドがあるかどうかを判断できます。

于 2011-04-05T21:59:43.913 に答える
2

技術的には、スレッドが完了する (参加する) まで待つ必要はありませんが、スレッドが完了を報告するまで待つ必要があります。したがって、すべてのスレッド間で共有されるCountdownEventのインスタンスを使用して、それを待つことができます。すべてのスレッドは、finally ブロックでイベントをデクリメントする必要があります。

void WorkerThread (object args)
{
  try
  {
    // actual work here
    ... 
  }
  finally
  {
    sharedCountdown.Signal();
  }
}

そして、シャットダウンを実行してスレッドの終了を待つとき:

// Notify all workers of shutdown
...

// Now wait for all workers to complete, up to 30 seconds
sharedCountdown.Wait(TimeSpan.FromSeconds(30));
于 2011-04-05T22:12:30.610 に答える
1

現在のアプローチはうまくいかない可能性があります。Parallel.ForEach実際に作成されるスレッドの数を制御することはできず、すべてのスレッド結合が並行して実行されるわけではありません。すべては、これらのタスクがスレッド プールでどのようにスケジュールされているかに依存します。その上、生成するすべてのスレッドは基本的に待機しているだけなので、非常に非効率的です。

これらのワーカー スレッドに、サービスのシャットダウン時に終了しなければならない重要なタスクがない場合は、代わりにすべてバックグラウンド スレッドにします。その場合、この問題にまったく対処する必要はありません。

于 2011-04-05T22:00:43.040 に答える