C#后台进程:使用安全吗?在 之前取消异步.RunworkerAsync.

本文关键字:取消 RunworkerAsync 异步 后台进程 安全 | 更新日期: 2023-09-27 18:35:23

当用户尝试双击按钮时,后台工作线程将启动两次。

这是一个很好的解决方法吗?

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // Some processing here
    Thread.Sleep(1000);
    button1.Invoke((MethodInvoker)delegate { button1.Enabled= true; });
}
// Run backgroundProcess
private void button1_Click(object sender, EventArgs e)
{
    this.button1.Enabled = false;
    backgroundWorker1.CancelAsync();
    backgroundWorker1.RunWorkerAsync();
}

C#后台进程:使用安全吗?在 之前取消异步.RunworkerAsync.

您可以使用backgroundWorker1_RunWorkerCompleted事件来启用 button1。 而不是在backgroundWorker1_DoWork启用

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
           this.button1.Enabled = true;
            //rest of operations
        }

你的代码有什么问题:

_DoWork启用按钮的意义较小,因为backgroundWorker1.RunWorkerAssync();会调用_DoWork()按钮启用,因此第二次单击也会被执行。

当你

要使用BackgrounWorker时,你必须照顾三个基本的事情。

  1. DoWork:如果需要,您可以处理业务逻辑的执行和工作的取消。
  2. RunWorker已完成:可以处理执行后任务。在这里,你想要启用按钮,所以你应该将适当的代码写入 RunWorkerFinished 事件。
  3. 如果要在任何执行点取消后台工作进程,请处理 WorkerSupportsCancel 属性。

     private void button1_Click(object sender, EventArgs e)
    {
        backgroundWorker1.WorkerSupportsCancellation = true;            
        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        button1.Enabled = false;
        backgroundWorker1.RunWorkerAsync();
    }
    void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        button1.Invoke((MethodInvoker)delegate { button1.Enabled = true; });
        backgroundWorker1.DoWork -= backgroundWorker1_DoWork;
        backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;
    }
    void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        for (int i = 0; i < 10; i++)
        {
            Thread.Sleep(1000);                
            AppendTextBox( "Hit: " + i.ToString() + Environment.NewLine);
            if (backgroundWorker1.CancellationPending)
            {
                break;
            }
        }
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
        }            
    }
    public void AppendTextBox(string value)
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action<string>(AppendTextBox), new object[] { value });
            return;
        }
        textBox1.Text += value;
    }
    private void button2_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy)
            backgroundWorker1.CancelAsync(); 
    }
    

如果工人实际上正在运行,那么几乎可以肯定不是。

取消是合作的。调用CancelAsync只是将CancellationPending标志设置为 true。由后台辅助角色定期检查此标志并响应取消。

正在运行的工作线程到达适当的点来检查该标志、检查它并做出响应的机会,所有这些都在这两行代码之间的时间间隔内:

backgroundWorker1.CancelAsync();
backgroundWorker1.RunWorkerAsync();

非常苗条。更有可能(如果工作线程正在运行)RunWorkerAsync会抛出InvalidOperationException,因为工作线程仍在运行。