如何暂停和恢复BackgroundWorker?

时间:2012-10-08 10:58:47

标签: c#

这就是我在代码中的做法: 在我做过的backgroundWorker DoWork活动中:

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);


        }

然后在暂停按钮点击事件中我做了:

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

在简历按钮点击事件中我做了:

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

但是当我点击开始这个过程时它不起作用:

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;
        }

只有当我点击进程启动时的恢复按钮然后单击暂停按钮时才会发生任何事情。

我希望当我点击开始进程按钮时,它会定期启动backgroundWorker,然后点击暂停按钮时会暂停,恢复按钮会恢复。

我做错了什么?有人可以修复我的代码吗?

5 个答案:

答案 0 :(得分:10)

在BackgroundWorker线程代码中,您需要找到可以安全“暂停”执行的位置。 ManualResetEvent是正确的代码方式。这篇文章可能有所帮助: Is there a way to indefinitely pause a thread?

基本上,在您希望允许暂停的工作线程代码中的几个选择点中,尝试插入:

_busy.WaitOne(Timeout.Infinite);

当你想暂停(从你的主线程)时,你使用:

_busy.Reset();

要恢复:

_busy.Set();

答案 1 :(得分:0)

您应该可以使用ManualResetEvent这样做......

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

...然后当你想暂停线程调用_busy.Reset()时...当你想重新启动它时,请致电_busy.Set()

此外,您可以将_busy.WaitOne();放在要暂停的任何位置。

答案 2 :(得分:0)

我一直在寻找这个帖子的答案,但我想出了我自己的解决方案,我只是想与你分享。希望这有效。

我有一个后台工作者,当我按下表单的关闭按钮时我想暂停它。问“你即将取消这个过程”,所以它应该暂停这个过程。

在您的课堂上声明bool pauseWorker = false;

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;
      }
   }
}

因此,这里的主要解决方案是控制BGWorker的DoWork事件的布尔声明。 希望此解决方案可以帮助您解决谢谢。

答案 3 :(得分:0)

我使用一个简单的类,该类利用System.Thread.Monitor和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) { }
    }
}

使用非常简单...

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
    }
}

答案 4 :(得分:-1)

这对我有用:

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();
}

注意:如果要更改界面的某些内容,则必须将其放在myChangeFunction()中,因为在DoWork()函数中将无效。希望这会有所帮助。