2017-08-22 5 views
0

複数のバックグラウンドワーカー(.net/c#内)を呼び出すメインスレッドがあります。 これらのスレッドのそれぞれは、実行可能ファイルを実行するためにプロセスを開始します。 プロセスが終了すると、メインスレッドに他のすべてのスレッドとそれぞれのプロセスを強制終了するように指示します。それらのすべてが停止した後、私はこれを知り、後処理のためにメインスレッドを実行し続ける必要があります。
これらの外部プロセスのリストを保持していますので、それらをすべて削除することに問題はありません。私の問題は、これらのすべてのバックグラウンド労働者を殺す方法です。 runworkercompletedメソッドがまだ複数回呼び出されているため、終了した最初のスレッド内からスレッドのリストを保持して終了させようとしました。 誰かが良い方法でそれらの労働者を殺す方法のパターンを持っていますか?私は何とか他の労働者の殺害を行うためにメインスレッドに通知する必要がありますか?複数のバックグラウンドワーカーの終了

+0

スレッド/プロセスの作成方法と開始方法のコードを投稿すると便利です –

答えて

0

this answerから、Backgroundworkerを殺す方法はないようです。しかし、this answerは、OnDoWorkを無効にし、Thread.CurrentThreadという参照を残して回避策を示しています。私はまだそれらのバックグラウンドワーカーにキャンセル通知をチェックさせようとします。

2

async/awaitとCancellationTokenSourcesの使用をお勧めします。私はBackgroundWorkersの使い方についてアドバイスをしますが、async/awaitははるかに便利で短くなるので、まずそれが優先されます。

async/awaitは、はるかに複雑さを増やすことなく、探している機能を提供するので便利です。

private async Task DoSomething(CancellationToken token) 
{ 
    // Do stuff 

    // Periodically check if someone has finished 
    if (Token.IsCancellationRequested) 
    { 
     // clean up 
     return; 
    } 
} 

非同期/コードは、いくつかの落とし穴、including deadlockを持って待っています:

private async void SomeEvent(object sender, EventArgs e) 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(); 
    var waiter1 = DoSomething(cts.Token); 
    var waiter2 = DoSomethingElse(cts.Token); 
    // etc. 

    // Wait for the first one to finish, then cancel 
    await Task.WhenAny(waiter1, waiter2, ...).ConfigureAwait(false); 
    cts.Cancel(); 

    // wait for the remainder to finish 
    await Task.WhenAll(waiter1, waiter2, ...).ConfigureAwait(false); 

    // Do Postprocessing 
} 

あなたの "ウェイターは" このようなものを見て。これは速いプロジェクトのように聞こえるので(私は間違っている可能性があります)、学習するには良い場所のように思えます。特に、大規模なコードベースがなくてもうまくいきます。詳細を知りたい場合は、スティーブン・クレアリーのブログ、特に彼のintroを開始するのがよいと思います。

一方、もしあなたが絶対にあなたがBackgroundWorkersを使いたいと思っているのであれば、私はあなたを責めませんが、私もあなたを羨ましく思いません。

まず、あなたの労働者は、他の誰かが最初に終了したかどうかを知る必要があります。 、そして、

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Error != null) 
    { 
     // Check for errors... 
    } 
    else if (e.Cancelled) 
    { 
     // Mark that this one has finished 
    } 
    else 
    { 
     // Assuming you have a set of BackgroundWorkers called "workers" 
     foreach (var bgw in workers) 
      bgw.CancelAsync(); 
     // other stuff... 
    } 
} 

取り消しを報告してくださいDoWorkメソッドの末尾にコードのビットを追加...

private void DoWork(object sender, DoWorkEventArgs e) 
{ 
    BackgroundWorker worker = sender as BackgroundWorker; 
    // Do stuff... 

    // When "RunWorkerCompleted" is called, let it know whether this worker has been cancelled. 
    e.Cancel = worker.CancellationPending;   
} 

そして、それはそれだ:他人のBackgroundWorkersをキャンセルするために、完成のBackgroundWorkerのRunWorkerCompletedメソッドを使用します。あなたは、あなたが以前に終了することができるかどうかを定期的に確認するためにworker.CancellationPendingを定期的にチェックすることもできますが、復帰前にworker.CancellationPendingをe.Cancelに割り当てることを忘れないでください!

1つ最後のこと:すべての作業者が終了したときに後処理を続行する場合は、特定の作業者が終了したときにマークを付けて(他の作業をキャンセルする)必要があります。彼らがいつ終わったのかを知る方法(後処理を始めることができます)。それは実行可能で、それほど難しくない - 私の頭の上から、私はDictionary<BackgroundWorker, bool>を使ってどの作業者が終了したのかを示します。それでも、それは非同期/待機で避けることのできるもう一つの混乱です。

関連する問題