2

チェックボックスの数に基づいて複数回呼び出す必要があるバックグラウンドワーカーがあります-チェックボックスの値を取得してList.

List repSelected = new List();

これは入力され、次のように繰り返されます。

foreach (string rep in repSelected)
{
    backgroundWorker1.RunWorkerAsync(rep);
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}

非同期の DoWork コードは次のようになります。

BackgroundWorker worker = sender as BackgroundWorker;
string rep = e.Argument.ToString();

if (worker.CancellationPending == true)
{
    e.Cancel = true;
}
else
{
    DirectoryExists(rep);
    ProcessRunner(rep); //Rars some large files - expensive
}

次に、プロセスは WorkerComplete を実行します。問題は、プロセスがワーカーの次の反復を実行するために戻ったときに、ワーカーがビジーであると言ってクラッシュすることです。ワーカーが WorkerCompleted ステータスを返したとしてもです。

ループの次の繰り返しの前にスレッドが閉じていることを確認するにはどうすればよいですか?

NB: バックグラウンド ワーカーに条件を設定しました!backgroundWorker1.IsBusy()が、これは (明らかに) 実行せずに残りの反復をスキップしただけです。

4

5 に答える 5

1

BackgroundWorker は非常にビジーです。これは、 の最初の呼び出しでbackgroundWorker1.RunWorkerAsync(rep);は何も待機せず、2 回目、3 回目、... の呼び出しがすぐに呼び出されるためです。

呼び出しごとに BackgroundWorker を作成する必要があります。

于 2012-05-17T10:46:40.423 に答える
1

parallel.foreach と複数のバックグラウンド ワーカーを使用できます。

Parallel.ForEach(YourListofStrings,
                 (q) =>
                 {
                     BackgroundWorker worker = new BackgroundWorker();
                     worker.DoWork += new DoWorkEventHandler(worker_DoWork);
                     worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
                     worker.RunWorkerAsync(q);
                 });
于 2012-05-17T11:10:18.947 に答える
1

各アイテムを順番に処理したい場合、タスクごとに個別のバックグラウンドワーカーを使用する理由はありません。そのため、foreach ループを DoWork メソッドに移動した方がよいでしょう。ただし、すべてのアイテムを並行して処理する場合は、アイテムごとに 1 つのバックグラウンド ワーカーを作成する必要があります。

于 2012-05-17T10:42:07.613 に答える
1

MSDN から:

バックグラウンド操作が既に実行されている場合、RunWorkerAsync を再度呼び出すと、InvalidOperationException が発生します。

そのため、 を使用してタスクのキューBackgroundWorkerを維持することはできません(また、前のタスクが完了するのを待たずに、すべてのタスクを順番にプッシュします)。これにはさまざまな解決策があります。たとえば、 を使い続けたい場合は、次のようにすることができます。BackgroundWorker

backgroundWorker1.RunWorkerAsync(repSelected);

次に、次のDoWorkようにメソッドを変更します。

BackgroundWorker worker = sender as BackgroundWorker;

foreach (string rep in (IEnumerable<string>)e.Argument)
{
    if (worker.CancellationPending == true)
    {
        e.Cancel = true;
        return;
    }
    else
    {
        DirectoryExists(rep);
        ProcessRunner(rep); //Rars some large files - expensive
    }
}

System.Threading.Tasks.Taskまたはを使用するなど、このタスクの実行方法を変更することを検討することもできますThreadPool(直接的または間接的に、ほとんどの並列操作はプールのキューに入れられます)。

于 2012-05-17T10:43:02.730 に答える
1

foreach-code は、すべての要素の作業をすぐにトリガーします。これが例外を受け取る理由です。

ワーカーを順次開始する場合は、RunWorkerAsync を開始時に 1 回だけ呼び出してから、WorkerComplete イベントごとに呼び出すことができます。しかし、worker-code で処理を foreach にしないのはなぜでしょうか?

于 2012-05-17T10:44:28.097 に答える