1. ホーム
  2. c#

[解決済み] BackgroundWorkerがキャンセルされるのを待つには?

2022-08-01 07:03:46

質問

以下のような 仮定 メソッドを考えてみましょう。

public class DoesStuff
{
    BackgroundWorker _worker = new BackgroundWorker();

    ...

    public void CancelDoingStuff()
    {
        _worker.CancelAsync();

        //todo: Figure out a way to wait for BackgroundWorker to be cancelled.
    }
}

BackgroundWorkerが終了するのを待つにはどうしたらよいでしょうか?


過去に人々は試しました。

while (_worker.IsBusy)
{
    Sleep(100);
}

しかし このデッドロックは というのは IsBusy がクリアされるのは RunWorkerCompleted イベントが処理されるまでクリアされず、そのイベントはアプリケーションがアイドル状態になるまで処理されないのです。Worker が終了するまで、アプリケーションはアイドル状態になりません。(さらに、それはビジー ループです。うんざりします。)

他の人は、それをクルーディングすることを提案しました。

while (_worker.IsBusy)
{
    Application.DoEvents();
}

この場合の問題は Application.DoEvents() を使用すると、現在キューにあるメッセージが処理されることになり、リエントランシーの問題が発生します(.NETはリエントラントではありません)。

私は、イベント同期オブジェクトを含む何らかの解決策を使用することを希望します。 を待ちます。 で待機し、ワーカーの RunWorkerCompleted イベントハンドラが設定します。のようなものです。

Event _workerDoneEvent = new WaitHandle();

public void CancelDoingStuff()
{
    _worker.CancelAsync();
    _workerDoneEvent.WaitOne();
}

private void RunWorkerCompletedEventHandler(sender object, RunWorkerCompletedEventArgs e)
{
    _workerDoneEvent.SetEvent();
}

イベントハンドラはアプリケーションがアイドルになるまで実行できず、アプリケーションはイベントを待っているためアイドルになりません。

では、BackgroundWorkerが終了するのを待つにはどうしたらよいのでしょうか。


更新 人々はこの質問で混乱しているようです。彼らは、私がBackgroundWorkerを次のように使用すると思っているようです。

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += MyWork;
worker.RunWorkerAsync();
WaitForWorkerToFinish(worker);

それは ではない それ、それは ではない 私がやっていることであり、それは ではなく ではありません。もしそうなら、バックグラウンド ワーカーを使用する意味はないでしょう。

どのように解決するのですか?

もし私があなたの要求を正しく理解していれば、次のようなことができるでしょう(コードはテストされていませんが、一般的なアイデアを示しています)。

private BackgroundWorker worker = new BackgroundWorker();
private AutoResetEvent _resetEvent = new AutoResetEvent(false);

public Form1()
{
    InitializeComponent();

    worker.DoWork += worker_DoWork;
}

public void Cancel()
{
    worker.CancelAsync();
    _resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    while(!e.Cancel)
    {
        // do something
    }

    _resetEvent.Set(); // signal that worker is done
}