如何在窗体的关闭事件上停止后台工作者,以避免 RaceOnRCWCleanup 错误,并在后台工作线程完成之前处理 fo

本文关键字:后台 工作 错误 RaceOnRCWCleanup 线程 fo 前处理 事件 工作者 窗体 | 更新日期: 2023-09-27 18:32:40

在 Form1 top 中,我添加了以下内容:

bool completed;
AutoResetEvent autoreset;

在构造函数中,我做到了:

completed = false;
autoreset = new AutoResetEvent(false);

在后台工作者DoWork事件中,我做了:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            while (true)
            {
                completed = true;
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    if (tempCpuValue >= (float?)nud1.Value || tempGpuValue >= (float?)nud1.Value)
                    {
                        soundPlay = true;
                        NudgeMe();
                    }
                    else
                    {
                        soundPlay = false;
                        stop_alarm = true;
                    }
                    tempCpuValue = Core.cpuView(pauseContinueDoWork,cpu,this,data,tempCpuValue,button1);
                    tempGpuValue = Core.gpuView(pauseContinueDoWork,data,tempGpuValue,button1);
                    this.Invoke(new Action(() => data = new List<string>()));
                    tempCpuValue = Core.cpuView(pauseContinueDoWork, cpu, this, data, tempCpuValue, button1);
                    tempGpuValue = Core.gpuView(pauseContinueDoWork, data, tempGpuValue, button1);
                    this.Invoke(new Action(() => listBox1.DataSource = null));
                    this.Invoke(new Action(() => listBox1.DataSource = data));

                    //listBox1.DataSource = data;
                }
            }
            autoreset.Set();
        }

然后在 Form1 结束事件中,我做了:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show("Are you Sure you want to Exit. Click Yes to Confirm and No to continue", "WinForm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                e.Cancel = true;
            }
            else
            {
                if (completed == true)
                {
                    this.backgroundWorker1.CancelAsync();
                    autoreset.WaitOne();
                }
            }

        }

当它执行 WaitOne() 时,表单刚回来显示在中间,程序正在冻结,我所能做的就是在 Visual Studio 中调试>停止调试

我想这样做是为了消除异常,我有时会得到一些关于多线程的 RaceOnRCWCleanup 的东西。

有时在关闭程序时,我在另一个类上了这个异常:

System.ObjectDisposedException was unhandled by user code
  HResult=-2146232798
  Message=Cannot access a disposed object.
Object name: 'Form1'.
  Source=System.Windows.Forms
  ObjectName=Form1
  StackTrace:
       at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
       at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
       at System.Windows.Forms.Control.Invoke(Delegate method)
       at HardwareMonitoring.Core.cpuView(Boolean pause, CpuTemperature cpuTemp, Form1 f1, List`1 myData, Nullable`1 myCpuTemp, Button b1) in d:'C-Sharp'HardwareMonitoring'HardwareMonitoring'Hardwaremonitoring'Core.cs:line 55
       at HardwareMonitoring.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in d:'C-Sharp'HardwareMonitoring'HardwareMonitoring'Hardwaremonitoring'Form1.cs:line 427
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException: 
就像在后台工作线程

完成作业之前设置的 form1 一样,后台工作线程 dowork 事件正在使用此类方法。

如何在窗体的关闭事件上停止后台工作者,以避免 RaceOnRCWCleanup 错误,并在后台工作线程完成之前处理 fo

假设 Bgw 是你的后台工作者,首先你将设置:

Bgw.WorkerSupportsCancellation = true;  

然后在您的DoWork委托中,您必须检查Bgw.CancelEnding是真还是假。

如果这是真的,则意味着后台工作者已被取消,如果不按原样继续,您将不得不中止该功能。

试试这个:

void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    while (!backgroundWorker1.CancellationPending)
    {
        if (tempCpuValue >= (float?)nud1.Value || tempGpuValue >= (float?)nud1.Value)
        {
            soundPlay = true;
            NudgeMe();
        }
        else
        {
            soundPlay = false;
            stop_alarm = true;
        }
        tempCpuValue = Core.cpuView(pauseContinueDoWork, cpu, this, data, tempCpuValue, button1);
        tempGpuValue = Core.gpuView(pauseContinueDoWork, data, tempGpuValue, button1);
        this.BeginInvoke(new Action(() => data = new List<string>()));
        tempCpuValue = Core.cpuView(pauseContinueDoWork, cpu, this, data, tempCpuValue, button1);
        tempGpuValue = Core.gpuView(pauseContinueDoWork, data, tempGpuValue, button1);
        this.BeginInvoke(new Action(() => listBox1.DataSource = null));
        this.BeginInvoke(new Action(() => listBox1.DataSource = data));
    }
    completed = true;
    autoreset.Set();
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    if (MessageBox.Show("Are you Sure you want to Exit. Click Yes to Confirm and No to continue", "WinForm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
    {
        e.Cancel = true;
    }
    else
    {
        if (!completed)
        {
            this.backgroundWorker1.CancelAsync();
            Hide(); // hide the form while waiting for the bw to terminate
            autoreset.WaitOne();
        }
    }
}

我已将呼叫从Invoke更改为BeginInvoke这应该可以缓解您的问题。