【问题标题】:How to pause and resume a BackgroundWorker?如何暂停和恢复 BackgroundWorker?
【发布时间】:2012-10-08 10:58:46
【问题描述】:

这就是我在代码中的做法: 在 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 常规然后当点击暂停按钮时它会暂停并且恢复按钮它将恢复。

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

【问题讨论】:

  • 已打开的问题进行编辑...aaa 并放弃了 :)
  • 只修改一个工人可以访问的布尔值?我会在 backgroundWorker 中解决这个问题,而不是通过暂停线程本身。
  • Aphelion 请给我一个例子谢谢。
  • _busy 是什么?

标签: c#


【解决方案1】:

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

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

_busy.WaitOne(Timeout.Infinite);

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

_busy.Reset();

然后继续:

_busy.Set();

【讨论】:

    【解决方案2】:

    您应该可以像这样使用ManualResetEvent 来执行此操作...

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

    ...然后当你想暂停线程调用_busy.Reset() ...并且当你想重新启动它时调用_busy.Set()

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

    【讨论】:

      【解决方案3】:

      我一直在寻找这个帖子的答案,但我想出了我自己的解决方案,我只想和你分享。希望这行得通。

      我有一个后台工作人员,我想在我点击表单的关闭按钮时暂停它。询问“您即将取消该过程”,因此它应该暂停该过程。

      在你的班级声明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 事件的布尔声明。 希望这个解决方案可以帮助您解决问题。谢谢。

      【讨论】:

      • 这会占用处理器周期,因为线程永远不会挂起。除非您知道暂停很短,否则最好使用锁。
      • 你是对的。但这只是很小的过程。我找不到任何解决方案,这就是我创建我的解决方案的原因。除了我不知道如何使用锁。
      【解决方案4】:

      我使用一个简单的类,它利用 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
          }
      }
      

      【讨论】:

        【解决方案5】:

        这对我有用:

        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() 函数中不起作用。希望这会有所帮助。

        【讨论】:

        • 此示例实际上并不是 OP 要求的暂停+恢复类型的示例。在这种情况下,使用BackgroundWorker 自己的CancelAsync() 方法和CancellationPending 属性而不是单独的bool 会更有意义。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-04
        • 1970-01-01
        相关资源
        最近更新 更多