Thread sleeping in a BackgroundWorker

2.9k views Asked by At

I wrote a simple app that adds 100000 lines of "Hello World" to a list using a BackgroundWorker.

Below is the code of the work that my backgroundworker is doing in a separate thread:

    private void BgWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
    {
        int min = 0;

        foreach (var hw in hwList)
        {
            //new ManualResetEvent(false).WaitOne(1);
            Thread.Sleep(1);
            int progress = Convert.ToInt32((Double)min / hwList.Count * 100);
            min++;
            bgWorker.ReportProgress(progress);
        }
    }

    // Updating the progress
    private void BgWorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs)
    {
        ProgressBar.Value = progressChangedEventArgs.ProgressPercentage;
    }

All is working fine, except that if I remove the Thread.Sleep(1) the BackgroundWorker doesn't report the progress anymore. (I suppose it needs some time). Suspending the thread for 1 ms actually makes the BackgroundWorker report the progress but it's very slow.

My question is, is there a way I can get rid of thread sleeping but at the same time making the BackgroundWorker report the progress correctly?

From my understanding, suspending the BackgroundWorker is inevitable, since the thread needs some time to perform the task, but I'm wondering if there's a workaround.

3

There are 3 answers

6
Marko On BEST ANSWER

I had issues where i was reporting progress to often, furthermore there is no reason to report the same progress so many times waste of cpu cycles.

 private void BgWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
    {
        int min = 0;
        int oldProgress = 0;
        foreach (var hw in hwList)
        {
            // new ManualResetEvent(false).WaitOne(1);
            // Thread.Sleep(1);
            int progress = Convert.ToInt32((Double)min / hwList.Count * 100);
            min++;

            // Only report progress when it changes
            if(progress != oldProgress){
                 bgWorker.ReportProgress(progress);
                 oldProgress = progress;
            }
        }
    }

    // Updating the progress
    private void BgWorkerOnProgressChanged(object sender, ProgressChangedEventArgs progressChangedEventArgs)
    {
        ProgressBar.Value = progressChangedEventArgs.ProgressPercentage;
    }
0
Graffito On

Instead of BackgroundWorker, I developed a class named SxProgress with a very simple interface that you may use in the following way :

 int DesiredLinesCount = 100000 ;
 List<string> Lines=new List<string>() ;
 object[] UserObjects = new object[] { Lines } ; 
 SxProgress.Execute("Building lines",DesiredLinesCount,true,false,
                    BuildLines_ExecInThread,UserObjects)) ;

 private bool BuildLines_ExecInThread(int ItemIndex,object[] UserObjects)
{
  // some sleep to slow down the process (demonstration purpose only)
  // if (ItemIndex % 10 ==0) System.Threading.Thread.Sleep(1) ; 
  List<string> Lines= (List<String>)UserObjects[0] ;
  Lines.Add("Hello world") ; 
  return true ; 
}

The SxProgress code is in the last message of this link

Note also that the class provides the same easy interface for parallel process, creating as many threads as cores in the computer with transparent dispatch of the items to the different threads.

0
Graffito On

will this work for WPF? Unfortunately no : The class encompasses a form (winforms) with progressbar, labels and stop button.

Possible solution : I never tried it.

It may work by adding to WPF project 2 references from the "Add reference" dialog form (in ".NET" tab),i.e. "System.Windows.forms" and "WindowsFormsIntegration".

Then, in source code, add "using System.Windows.Forms;"
and "using System.Windows.Forms.Integration;"