c# - 为什么我不能使 BackgroundWorker() 按预期工作?

标签 c# winforms thread-safety backgroundworker

我正在尝试运行以下代码来测试 BackgroundWorker,但这给我带来了很多问题:

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace BackgroundWorkingTest
{
    public partial class Form1 : Form
    {
        BackgroundWorker backgroundWorker1 = new BackgroundWorker();
        int counter;

        public Form1()
        {
            InitializeComponent();

            backgroundWorker1 = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };

            backgroundWorker1.DoWork += BackgroundWorker1_DoWork;
            backgroundWorker1.ProgressChanged += BackgroundWorker1_ProgressChanged;
            backgroundWorker1.RunWorkerCompleted += BackgroundWorker1_RunWorkerCompleted;
        }

        private void StartButton_Click(object sender, EventArgs e) // Start
        {
            counter = 0;
            backgroundWorker1.RunWorkerAsync();
        }

        private void CancelButton_Click(object sender, EventArgs e) // Cancel
        {
            backgroundWorker1.CancelAsync();
            progressLabel.Text = "0";
        }

        private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // DoWork
        {
            int i;

            for (i = 0; i < 123456; i++)
            {
//              Application.DoEvents();    // This line doesn't help
//              Thread.Sleep(1);           // Enable this line solve the problem

                backgroundWorker1.ReportProgress(i + 1);
                counter++;

                if (backgroundWorker1.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
            }
        }

        private void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) // Progress
        {
            progressLabel.Text = counter.ToString();
            progressLabel.Refresh();
        }

        private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) // Completed
        {
            if (e.Cancelled)
                MessageBox.Show("Operation Cancelled");
            else
                MessageBox.Show("Operation Completed");
        }
    }
}

1. 例如,在 BackgroundWorker1_DoWork() 方法中您可以看到命令:

Thread.Sleep(1);

如果我禁用它,则“取消”按钮没有响应。我点击它几次,但它没有停止进程,我也没有收到“操作已取消”消息。

如果我启用它,它就会工作,但我不想在我的线程中使用任何 Sleep(1) 命令,因为它只会减慢进程,我不希望这样。

如果我启用命令:

Application.DoEvents();

它根本没有帮助,“取消”按钮在计数过程中也没有响应。

2. 我看到的另一个问题是,如果我使用命令:

progressLabel.Refresh();

在 ProgressChanged() 事件中,发生了一些非常奇怪的事情。我可以在面板上看到它已完成计数,并在标签上显示:“123456”。但是 之后 花了将近一分钟才显示“操作已完成”消息。

如果在标签显示“123456”后,我在 ProgressChanged() 方法中设置了一个断点,然后我看到它一直进入 e.ProgressPercentage 参数一直上升的方法。

怎么可能呢?如果我在面板上看到“123456”,它不是说进程已经完成了吗?如果是,那它为什么不立即向我显示“操作已完成”消息?

3. 如果我删除“progressLabel.Refresh()”行,那么我会在标签显示“123456”后立即收到“操作已完成”消息,但随后却没有t 显示 0 到 123456 之间的计数(正如我在启用 Refresh() 命令时看到的那样)。

4. 还有一点我不太明白:

当我更改代码以使用多个 BackgroundWorker 的数组而不是一个时:

BackgroundWorker[] backgroundWorker1 = new ....

启用 Sleep(1) 后,我没有收到任何错误消息,尽管所有线程都将文本设置为相同的标签,并将值写入相同的计数器。

有意义吗?从多个 BackgroundWorker 线程同时更新同一标签时,我怎么没有收到任何运行时错误?

非常感谢。

最佳答案

您过于频繁地报告进度:

for (i = 0; i < 123456; i++)
{
    backgroundWorker1.ReportProgress(i + 1);

...并且窗口的消息循环被消息溢出。因此它无法及时处理 CancelButton_Click 事件。

关于c# - 为什么我不能使 BackgroundWorker() 按预期工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73561953/

相关文章:

c# - 在缓存中找不到类型 - UWP Windows 10

c# - ConcurrentBag 字符串并在 Parallel.ForEach 中使用 .Contains

c# - 为什么有时在查看文件/目录的更改时它没有将标志更改为 true?

c# - 具有多色 TreeNode 文本的 TreeView

java - DefaultThreadFactory本身是线程安全的吗?

java - 将读取同步到 java 集合

C# 对象(创建和使用)

c# - 统一 3D : Footstep sounds looping the first few milliseconds instead of playing the full sound then looping

c# - 通过多线程提高性能

c# - 如何在按钮名称下加下划线