0

I want a background worker to continue running and occasionally update the user interface. My first idea was to use a BackgroundWorker and in its completed event just fire it up again.

Is using a BackgroundWorker in this fashion acceptable? Or are there potential issues from using the completed event to trigger the worker?


Below is some Pseudo code of what my intentions are

class Program
{
    private static BackgroundWorker worker;
    private static Int32 runs = 0;

    static void Main(string[] args)
    {
        worker = new BackgroundWorker();
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync(runs);
        Console.ReadLine();
    }

    static void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //Do time consuming work
        Thread.Sleep(3000);
    }

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //Update the UI and start time consuming work again
        runs++;
        Console.WriteLine("Completed run #" + runs);
        worker.RunWorkerAsync();
    }
}

4 Answers 4

1

It's not absolutely clear from the spec whether a BackgroundWorker could be considered to be still running when the RunWorkerCompleted event is triggered - in which case calling RunWorkerAsync() will cause an exception.

Because the spec is unclear I wouldn't re-use the BackgroundWorker object: it might work or it might break on different releases of .Net. Just create a new one in the worker_RunWorkerCompleted() handler.

If you search for BackgroundWorker reuse, you will find several posts suggesting there might be some issues in this area.

2

Using the Backgroundworker in this fashion is not acceptable. That's why it specifically has a ProgressChanged event. I would suggest rewriting your app to accept a MaxRuns integer and pass that once to the BGW. Then inside the BGW worker loop over each run. At the bottom of each run, you then report progress.

I know your example is a shortened and is a console app. But in case you ever have a forms app, you could set up a progress bar from 0 - MaxRuns, and have the BGW worker report it's progress back to the UI so the UI can move the progress bar.

On last tip: progress reporting has a parameter named ProgressPercentage. It is just an int, which can be negative or > 100. So don't feel constrained between 0 and 100.

EDIT: Example Code

class Program

{ private static BackgroundWorker worker; private static Int32 maxRuns = 3333;

static void Main(string[] args)
{
    worker = new BackgroundWorker();
    worker.DoWork += worker_DoWork;
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    worker.ProgressChanged += worker_ProgressChanged;
    worker.RunWorkerAsync(maxRuns);
    Console.ReadLine();
}

static void worker_DoWork(object sender, DoWorkEventArgs e)
{
    int totalRuns = (int)e.Argument;
    for (int i = 0; i < totalRuns; i++)
    {
        var sw = Stopwatch.StartNew();
        //Do time consuming work 
        Thread.Sleep(3000);
        worker.ReportProgress(i, sw.Elapsed);
    }
}

// This method runs in the foreground thread while the background worker is busy.
static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // e.ProgressPercentage is not a true percentage.  Rather it is the Run number.
    var percent = (100 * e.ProgressPercentage) / maxRuns;
    var elapsed = (TimeSpan)e.UserState;
    Console.WriteLine(string.Format("{0}% complete.  Run {1} of {2} took {3}.", percent, e.ProgressPercentage, maxRuns, elapsed));
}

static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Console.WriteLine("Background Completed.");
}

}

3
  • I like your idea of using the Progress Changed event but I am particularly interested in the WorkerCompleted event and if there are any particular problems with using it, and if there are problems what are they.
    – GER
    Commented Sep 3, 2014 at 19:29
  • I can only encourage you to use the BGW in a proper fashion. If you step back to look at the big picture of what you're application is trying to do, hopefully you will realize the ProgressChanged event is a classic fit.
    – Rick Davin
    Commented Sep 4, 2014 at 13:20
  • @GER But the ProgressChanged event is exactly the semanitcs you're looking for; why try to hammer WorkerCompleted to be something its not?
    – Andy
    Commented Sep 9, 2015 at 15:18
0

if you just want to restart it immediately, it would seem to be a better option to just wrap the DoWork function body in an endless loop.

0

Just try to run the code... It will throw an exception saying:

This BackgroundWorker is currently busy and cannot run multiple tasks concurrently.
at System.ComponentModel.BackgroundWorker.RunWorkerAsync(Object argument)
at System.ComponentModel.BackgroundWorker.RunWorkerAsync()

So it is even not possible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.