none
How to Pause or sleep the background worker thread

    Question

  • Posted - 05/03/2006 :  07:03:30 AM    
    I m using the background worker thread to done the task. i m using this because my application required the update of the GUI based on the status of work so background worker thread will be helpful to me. Now the issue is that i have one button of pause/resume to pause/resume the working of this background worker thread. i haven't found any function of this component to perform this task.
    Kindly help me in this regard
    Thanks in advance
    Wednesday, May 03, 2006 12:12 PM

Answers

  • Well, seems like the class itself doesn't provide this behavior, however there's a workaround.

    You can monitor some class member inside worker's procedure and call Sleep from within the worker. I think something like this should work fine:

    class MyWorkerClass
    {
      ...
      volatile bool m_bPaused  = false;
      // Public property to control worker execution
      public bool Paused
      {
        get
        {
          return m_bPaused;
        }

        set
        {
          m_bPaused = value;
        }
      }

      long ThreadFunc (BackgroundWorker worker, DoWorkEventArgs e)
      {
        ...
        // While Paused property set to true
        while (m_bPaused)
        {
          // Pause execution for some time
          System.Threading.Thread.Sleep (100);

          // Maybe you would like to check if the worker cancelled
          if (worker.CancellationPending)
          {
            e.Cancel = true;
            // return from method here
          }
        }
      }
      ...
    }

     

    Wednesday, May 03, 2006 6:50 PM

All replies

  • System.Threading.Thread.Sleep method.
    Wednesday, May 03, 2006 4:23 PM
  • i have checked this out but its stops my application. At backend the background worker thread continue its execution. may be i m in fault if i m then kindly let me know so that i will recheck this case once again As far as i know i have tested that.

    Thanks

    Wednesday, May 03, 2006 4:29 PM
  • Use Thread.Suspend to pause thread execution and then Thread.Resume to make it running afterwards.
    Wednesday, May 03, 2006 6:18 PM
  • yes these function can be used but these functions belong to the namespace System.Threading.Thread while Background worker belongs to the "System.ComponentModel.BackgroundWorker" and there is no such function in that.
    Wednesday, May 03, 2006 6:25 PM
  • Well, seems like the class itself doesn't provide this behavior, however there's a workaround.

    You can monitor some class member inside worker's procedure and call Sleep from within the worker. I think something like this should work fine:

    class MyWorkerClass
    {
      ...
      volatile bool m_bPaused  = false;
      // Public property to control worker execution
      public bool Paused
      {
        get
        {
          return m_bPaused;
        }

        set
        {
          m_bPaused = value;
        }
      }

      long ThreadFunc (BackgroundWorker worker, DoWorkEventArgs e)
      {
        ...
        // While Paused property set to true
        while (m_bPaused)
        {
          // Pause execution for some time
          System.Threading.Thread.Sleep (100);

          // Maybe you would like to check if the worker cancelled
          if (worker.CancellationPending)
          {
            e.Cancel = true;
            // return from method here
          }
        }
      }
      ...
    }

     

    Wednesday, May 03, 2006 6:50 PM
  • I have been working on such a topic for a while and now I find a way (but may contains bugs).

            void Button1Click(object sender, EventArgs e)
            {
                backgroundWorker1.RunWorkerAsync();
            }
           
            void Button2Click(object sender, EventArgs e)
            {
                if (button2.Text == "Pause") {
                    Active = false;
                    button2.Text = "Resume";
                } else {
                    Active = true;
                    button2.Text = "Pause";
                }
            }
         
            void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
            {
                int i = 1000;
                while(i > 0) {
                    if (Active) {
                        i--;
                        backgroundWorker1.ReportProgress(i);
                        System.Threading.Thread.Sleep(10);
                    }
                }
            }
           
            private bool Active = true;
           
            void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
            {
                richTextBox1.AppendText(e.ProgressPercentage.ToString() + Environment.NewLine);
            }
           
            void BackgroundWorker1RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("Completed.");
            }
    In the sample code, a Active flag is used. I know this may not suit your need, but it meets my requirements well.
    Thursday, April 26, 2007 8:48 AM
  • To do this without sleeping and unnecessary delays, use a ManualResetEvent.  Call Set() to allow the worker to execute, Reset() to block it.  In the worker, call WaitOne() to block.
    Thursday, April 26, 2007 2:14 PM
  • Yes, yes, it is a better way to use a MenualResetEvent. I have updated my sample code like this:

            void Button1Click(object sender, EventArgs e)
            {
                backgroundWorker1.RunWorkerAsync();
            }
           
            void Button2Click(object sender, EventArgs e)
            {
                if (button2.Text == "Pause") {
                    locker.Reset();
                    button2.Text = "Resume";
                } else {
                    locker.Set();
                    button2.Text = "Pause";
                }
            }
         
            void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
            {
                int i = 1000;
                while(i > 0) {
                       locker.WaitOne();
                        i--;
                        backgroundWorker1.ReportProgress(i);
                        System.Threading.Thread.Sleep(10);
                }
            }
           
            private ManualResetEvent locker = new ManualResetEvent(true);
           
            void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
            {
                richTextBox1.AppendText(e.ProgressPercentage.ToString() + Environment.NewLine);
            }
           
            void BackgroundWorker1RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("Completed.");
            }

    Friday, April 27, 2007 12:50 AM
  •  ShellShock wrote:
    System.Threading.Thread.Sleep method.
    Thread.Sleep is poor design.
    Friday, April 27, 2007 2:55 AM
  •  Vladimir Zinchenko wrote:
    Use Thread.Suspend to pause thread execution and then Thread.Resume to make it running afterwards.
    Thread.Suspend is obsolete.  Plus, you can't externally get the Thread object used by the background worker.  BackgroundWorker uses a thread pool thread, if you could use Thread.Suspend it would be really bad idea.
    Friday, April 27, 2007 2:59 AM
  • Use of Thread.Sleep() is the last way for pausing a thread when the time of pause is not known. You will have to loop infinite with a Sleep with some milliseconds and check if it can proceed. If you use Thread.Suspend / Resume, you will get warning saying that they are marked as obsolete and use Monitor or Waithandles instead. The method that is executed asynchronously should check frequently for a flag or should try to acquire a handle, every few loop cycles or every few statements.
    Friday, April 27, 2007 8:16 AM
  • "pausing" a background worker thread is a waste of a thread pool thread.  There's a limited number of thread pool threads per process and they are also used by the framework; if you "pause" thread pool threads you run the risk of staving the framework of threads and you'll create bigger problems.

     

    Any background thread should do what it needs to do and terminate as quickly as possible.  I would suggest if the operation is "pausable" then it's also cancel-able; in which case simply offer the ability to cancel instead of pause and exit the background worker until the user requests the operation start again.

    Friday, April 27, 2007 11:18 AM
  •  Peter Ritchie wrote:

    I would suggest if the operation is "pausable" then it's also cancel-able...


    I hardly think this assumption can be made without knowing more about the circumstances of the application. However, implementation details don't have to match what's happening from the user's perspective. By that I mean, when the user wants to "pause" the background worker, you should save the state of the process that the background worker is performing, then cancel the worker, releasing its thread back to the thread pool. When the user "resumes", create a new background worker using the saved state, and continue processing.
    Saturday, April 28, 2007 4:39 AM
  •  CommonGenius.com wrote:

     Peter Ritchie wrote:

    I would suggest if the operation is "pausable" then it's also cancel-able...


    I hardly think this assumption can be made without knowing more about the circumstances of the application. However, implementation details don't have to match what's happening from the user's perspective. By that I mean, when the user wants to "pause" the background worker, you should save the state of the process that the background worker is performing, then cancel the worker, releasing its thread back to the thread pool. When the user "resumes", create a new background worker using the saved state, and continue processing.

    Since Thread.Suspend is impossible with a BackgroundWorker the logic in the DoWork requires some sort of flag to "pause" it. To cancel the operation the variables used in whatever iterative logic would have to be cached, yes; but it's still cancel-able.  I would assert anything that is truly pausable is also cancel-able (the qualification being that Thread.Suspend should not be used at all). I could have qualified my statement as "...if you think the operation is 'pausable' then..." which, yes, was assumed in the fact the OP implied no code had yet been written.

     

    But, yes, in the context of "pause" in the user interface, what is performed under the covers is an implementation detail: it could be a call in the DoWork event handler to a WaitOne method to put that thread pool thread into a wait state (not recommended) or it could mean saving the state required to restart the BackgroundWorker, canceling it, and letting it get collected (recommended) to be recreated when unpaused.

    Saturday, April 28, 2007 1:37 PM
  •         
    Peter Ritchie said:

    Since Thread.Suspend is impossible with a BackgroundWorker the logic in the DoWork

    What to you mean by this Peter?  It seems to work fine for me.
     
          protected override void OnDoWork(DoWorkEventArgs e)
          {
             // Sleep for given wait time in milliseconds
             System.Threading.Thread.Sleep(10000);
              ..
         }

    My design requirement is for my tray app to wait 6 minutes after loading (normally system boot-up), then check for updates.  If updates are available the user gets a dialog prompting for download now or not.

    I originally used this line from my tasktray Form constructor, with the first line calling Sleep to sleep the thread for a few minutes.
    ThreadPool.QueueUserWorkItem(new WaitCallback(AutoUpdate.CheckForUpdates), new ThreadParams(this, C_DELAY_UPDATE))

    It worked fine however I was using MessageBox.ShowDialog() within that thread to prompt for updates and was concerned that perhaps MessageBox.ShowDialog()  might not automatically marshall to the UI thread or would cause some errors in that regard so I thought I'd try using BackgroundWorker instead.

    The BW worker runs just as fine as the previous ;) and should not have any UI thread issues, however I guess upon reflection I wanted to be sure firing sleeping the thread was an OK approach, which led me here.  In this context are there any issues with this approach? 

    I can just as easily create a timer with to fire off my upgrade check, which also works well, but I guess I'd like to understand a little more about this from an expert:
    tmrUpgrade = new System.Threading.Timer(cbCheckUpgrade, null, C_DELAY_UPDATE, System.Threading.Timeout.Infinite);

    Regards
      Ewart.
    Monday, February 23, 2009 2:17 AM
  • Thread.Sleep is possible from a BackgroundWorker thread because you can call that method within the DoWork event handler.  Thread.Suspend isn't possible because you need a reference to a thread object and the thread object used by the BackgroundWorker is a thread-pool thread.  By calling Thread.Suspend on another thread, you have no way of knowing is the thread you're suspending is still the thread being used by your BackgroundWorker--it could have been reused by something else, even by the framework.

    I don't recommend using Thread.Sleep as a timing mechanism to execute code.  In your case where you'd want to pause for 6 minutes; using sleep would mean you can't exit that thread until Sleep returns; which means your application can't reliably exit until that thread exits.  Yes, there's ways around that; but they all deal with abnormal termination of the thread which can lead to other problems.

    If you want to perform some sort of action periodically; a timer is your best bet.  If you know you're only going to have a single elapsed event occurring at a time, or you're only going to have one timer, and you want it to do something with the UI the System.Windows.Forms.Timer class would be a better choice.  It's Tick event (equivalent to the System.Thread.Timer.Elapsed event) runs on the GUI thread.

    http://www.peterRitchie.com/blog
    Monday, February 23, 2009 2:52 PM
  • All makes perfect sense to me - I shall continue using the timer but change it to a Forms timer from a threading one - thanks Peter.
    • Proposed as answer by mike-webdude Wednesday, July 15, 2009 4:27 PM
    Monday, February 23, 2009 6:53 PM
  • I tried something a bit different take a look:  My AutoResetEvent will allow me to stop only my BackgroundWorker and not the Applications Thread, I use the WaitCancellationPending to see if my Thread is currently Awaiting Cancellation Pending, this was helpful for using a MessageBox that asked the user if they were sure they wanted to cancel the current operation, and put the Thread in a holding state until it recieves a response.  The next step would be to allow the application to override the action if it does not recieves a response in a reasonable amount of time.  We'll see.

     

    public class MyBackgroundWorker : BackgroundWorker
    {
      private AutoResetEvent _resetEvent = new AutoResetEvent(false);
    public bool WaitCancellationPending { get; set; } public void WaitOne() { _resetEvent.WaitOne(); } public void Set() { _resetEvent.Set(); } }

     

     

     

    • Edited by mike-webdude Wednesday, July 15, 2009 4:40 PM
    • Proposed as answer by mike-webdude Wednesday, July 15, 2009 4:42 PM
    Wednesday, July 15, 2009 4:36 PM
  • public class MyBackgroundWorker : BackgroundWorker
    {
      private AutoResetEvent _resetEvent = new AutoResetEvent(false);
      public bool WaitCancellationPending { get; set; }
      public void WaitOne()
      {
        _resetEvent.WaitOne();
      }
      public void Set()
      {
        _resetEvent.Set();
      }
    }
    



    me likey.


    Saturday, November 07, 2009 10:07 AM