简体   繁体   中英

How to pause and resume a BackgroundWorker?

This is how I did it in my code: In the backgroundWorker DoWork event I did:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            _busy.WaitOne();
                this.Invoke(new MethodInvoker(delegate { label2.Text = "Website To Crawl: "; }));
                this.Invoke(new MethodInvoker(delegate { label4.Text = mainUrl; }));
                webCrawler(mainUrl, levelsToCrawl, e);


        }

Then in the pause button click event I did:

private void button4_Click(object sender, EventArgs e)
        {
            _busy.Reset();
        }

In the resume button click event I did:

private void button5_Click(object sender, EventArgs e)
        {
            _busy.Set();
        }

But it's not working when I click to start the process:

private void button1_Click(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
            button1.Enabled = false;
            this.Text = "Processing...";
            label6.Text = "Processing...";
            label6.Visible = true;
            button2.Enabled = false;
            checkBox1.Enabled = false;
            checkBox2.Enabled = false;
            numericUpDown1.Enabled = false;
            button3.Enabled = true;
        }

Nothing happen only when I click the resume button the process start then when I click the pause button nothing happen.

I want that when I click the start process button it will start the backgroundWorker regular then when clicking the pause button it will pause and the resume button it will resume.

What did I do wrong ? Can someone fix my code ?

In your BackgroundWorker thread code, you need to find places that are safe to "pause" execution. The ManualResetEvent is the right way to code. This other post might help: Is there a way to indefinitely pause a thread?

Basically, in a few choice points in your worker thread code where you want to allow it to pause, try inserting:

_busy.WaitOne(Timeout.Infinite);

And when you want to pause (from your main thread) you use:

_busy.Reset();

And to resume:

_busy.Set();

You should be able to do this using the ManualResetEvent like this ...

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{
    _busy.WaitOne();
    test(mainUrl, levelsToCrawl, e); 
}

... and then when you want to pause the thread call _busy.Reset() ... and when you want to restart it call _busy.Set() .

Additionally, you can place _busy.WaitOne(); anywhere you want to pause.

I've been looking for the answer of this thread but I come up with my own solution i made and i just wanna share it with you. hope this works.

I have a background worker and i want to pause it when i hit close button of my form. asking "You are about to cancel the process" so it should pause the process.

declare bool pauseWorker = false; on your class.

private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
   while (condition)
   {
      if (pauseWorker == true)
      {
         while (pauseWorker == true)
         {
            if (pauseWorker == false) break;
         }
      }
      else
      {
         //continue process... your code here
      }
   }
}

private void frmCmsnDownload_FormClosing(object sender, FormClosingEventArgs e)
{
   if (bgWorker.IsBusy)
   {
      pauseWorker = true; //this will trigger the dowork event to loop that
                          //checks if pauseWorker is set to false
      DiaglogResult x = MessageBox.Show("You are about cancel the process", "Close", MessageBoxButtons.YesNo);
      if (x == DialogResult.Yes) bgWorker.CancelAsync();
      else 
      { 
         e.Cancel = true; 
         pauseWorker = false; //if the user click no
                              //the do work will continue the process
         return;
      }
   }
}

Therefore the main solution here is the boolean declaration that controls the DoWork event of BGWorker. Hope this solution helps your problem. Thank you.

I use a simple class that utilizes System.Thread.Monitor and lock()...

public class ThreadPauseState {
    private object _lock = new object();
    private bool _paused = false;

    public bool Paused {
        get { return _paused; }
        set {
            if(_paused != value) {
                if(value) {
                    Monitor.Enter(_lock);
                    _paused = true;
                } else {
                    _paused = false;
                    Monitor.Exit(_lock);
                }
            }
        }
    }

    public void Wait() {
        lock(_lock) { }
    }
}

Using it is very simple...

private ThreadPauseState _state = new ThreadPauseState();

private void btnPause_Click(object sender, EventArgs e) {
    _state.Paused = true;
}

private void btnResume_Click(object sender, EventArgs e) {
    _state.Paused = false;
}

private void btnCancel_Click(object sender, EventArgs e) {
    backgroundWorker1.CancelAsync();
    _state.Paused = false; // needed if you cancel while paused
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
    var worker = (BackgroundWorker)sender;
    for(var _ = 0; _ < 100; _++) {
        _state.Wait();
        if(worker.CancellationPending) return;
        Thread.Sleep(100); // or whatever your work is
    }
}

This works for me:

bool work = true;
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
backgroundWorker1.ProgressChanged += myChangeFunction;
backgroundWorker1.RunWorkerAsync();

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    while (true && work)
    {
        // Your code here

        backgroundWorker1.ReportProgress(0);
        Thread.Sleep(1000);
    }
    e.Cancel = true;
}
private void myChangeFunction(object sender, ProgressChangedEventArgs e)
{
  // Here you can change label.text or whatever thing the interface needs to change.
}
private void Stop()
{
    work = false;
}
private void Start()
{
    work = true;
    backgroundWorker1.RunWorkerAsync();
}

NOTE: If you want to change something of the interface, you have to put it in the myChangeFunction(), because in the DoWork() function will not work. Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM