web-dev-qa-db-ja.com

BackgroundWorkerが終了してコンソールアプリケーションを終了するまで待機する方法

Stackoverflowに投稿されている例の1つを使用して、バックグラウンドワーカーをテストするためのサンプルコンソールアプリケーションを作成しました。 mainメソッドで始まるbackgroundworkerがありますが、mainメソッドでconsole.readkeyを記述したため、Enterキーを押すと、操作の途中で終了します。しかし、私はバックグラウンドワーカーが仕事を終えてアプリケーションを終了するまでそれを待ってもらいたいです。これは私のコードです。

class Program
{
    private static BackgroundWorker worker = new BackgroundWorker();
    private event EventHandler BackgroundWorkFinished;

    static void Main(string[] args)
    {
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.WorkerReportsProgress = true;
        worker.WorkerSupportsCancellation = true;

        Console.WriteLine("Starting Application...");

        worker.RunWorkerAsync();
        Console.ReadKey();
    }

    static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Console.WriteLine(e.ProgressPercentage.ToString());
    }

    static void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        Console.WriteLine("Starting to do some work now...");
        int i;
        for (i = 1; i < 10; i++)
        {
            Thread.Sleep(1000);
            worker.ReportProgress(Convert.ToInt32((100.0 * i) / 10));
        }

        e.Result = i;
    }

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine("Value Of i = " + e.Result.ToString());
        Console.WriteLine("Done now...");
    }
}
21
Soham Dasgupta

BackgroundWorkerとメインスレッド間の通信方法については、 BackgroundWorkerがキャンセルされるのを待つ方法 投稿を参照してください。

基本的に、DoWorkの終了時に設定したイベントを使用して、DoWorkが完了したことを通知する必要があります。次に、メインスレッドのそのイベントでWaitOne()を実行します。

10

Bgwの主な目的は、Windows MessageQueueと対話することです。つまり、WinFormsおよびWPFアプリケーションで最も役立ちます。

コンソールアプリケーションは、Bgwを使用またはテストするのに適切な場所ではありません。奇妙な結果が得られます。重要なポイントでManagedThreadIdを出力して、何が起こるかを確認します。

そして、いくつかの標準的なアドバイス:worker_RunWorkerCompleted()e.Errorをチェックする必要があります。 現時点では、空のcatch{}ブロックがあるのと同じです。
処理がより複雑なe.Resultを読み取ると、DoWorkからのエラーがスローされるようになりました。

4
Henk Holterman

これは私が今やったことです。しかし、console.readkey()は機能していません。アプリケーションはReadKey()関数を待機していません。

_class Program
{
    private static BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
    private static AutoResetEvent resetEvent = new AutoResetEvent(false);
    static void Main(string[] args)
    {
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.WorkerReportsProgress = true;

        Console.WriteLine("Starting Application...");

        worker.RunWorkerAsync();
        resetEvent.WaitOne();

        Console.ReadKey();
    }

    static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Console.WriteLine(e.ProgressPercentage.ToString());
    }

    static void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        Console.WriteLine("Starting to do some work now...");
        int i;
        for (i = 1; i < 10; i++)
        {
            Thread.Sleep(1000);
            worker.ReportProgress(Convert.ToInt32((100.0 * i) / 10));
        }

        e.Result = i;

        resetEvent.Set();
    }

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Console.WriteLine("Value Of i = " + e.Result.ToString());
        Console.WriteLine("Done now...");
    }

}
_

修正の編集:resetEvent.Set()RunWorkerCompletedではなく、内部DoWorkに移動しました。メインスレッドがイベントを待機しているため、Completedイベントハンドラーは呼び出されません。

2
Soham Dasgupta