C#,在单独的线程中解析数据并更新 GUI

C#, parsing data in a separate thread and updating GUI

大家。基本上我要实现的工作流程如下:

由于截止日期不远,我从一个名为 Termie 的开源项目开始,它实现了一个简单的串行接口,还提供了一个开箱即用的通信配置表单。 为了执行多线程操作,我使用了 BackgroundWorker

private BackgroundWorker backgroundPressure = new BackgroundWorker();

我在主窗体的构造方法中初始化的:

public consoleForm()
{
    ...
    // Initialize background worker to separate GUI from data collection
    backgroundPressure.DoWork += new DoWorkEventHandler(backgroundPressure_DoWork);
    backgroundPressure.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundPressure_RunWorkerCompleted);
    backgroundPressure.ProgressChanged += new ProgressChangedEventHandler(backgroundPressure_ProgressChanged);
    backgroundPressure.WorkerReportsProgress = true;
    backgroundPressure.WorkerSupportsCancellation = true;
}

传输开始时,调用backgroundPressure的RunworkerAsync方法:

if(!backgroundPressure.IsBusy)
{
    backgroundPressure.RunWorkerAsync();
}

正确处理了DoWork事件,我的程序正确地进入了具有以下代码的处理程序方法:

    protected void backgroundPressure_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker sendingWorker = (BackgroundWorker)sender;

        BeginInvoke((MethodInvoker)delegate
        {
            pressureChart.Series.Clear();
            pressureData.Clear();
            timeAxis.Clear();

            foreach (string name in pressureSensorNames)
            {
                pressureChart.Series.Add(name);
            }
        });

        Stopwatch sto = new Stopwatch();
        int linenumber = syncWithLogger("pres");

        int debugs = linenumber;

        while (linenumber == -1)
        {
            Thread.Sleep(100);
            BeginInvoke((MethodInvoker)delegate
            {
                linenumber = syncWithLogger("pres");
            });
        }

        sto.Start();

        long elapsed = sto.ElapsedMilliseconds;

        while (!sendingWorker.CancellationPending)
        {
            BeginInvoke((MethodInvoker)delegate
            {
                try
                {
                    elapsed = sto.ElapsedMilliseconds;

                    pressureChartUpdate(linenumber, elapsed);
                    imuChartUpdate(linenumber + 1, elapsed);

                    linenumber += 2;
                    Thread.Sleep(100);
                }
                catch(Exception ex)
                {
                    if(ex is FormatException)
                    {
                        Thread.Sleep(100);
                        // Wait and go on
                    }
                    else if(ex is ArgumentOutOfRangeException)
                    {
                        Thread.Sleep(100);
                        // Wait and go on
                    }
                }

            });

            sendingWorker.ReportProgress(10, 100);

            BeginInvoke((MethodInvoker)delegate
            {
                samplesAcquiredStatus.Text = sto.ElapsedMilliseconds.ToString();
            });


            e.Cancel = true;
            sto.Stop();

        }
    }

一切正常,直到 while (!sendingWorker.CancellationPending) 块。当它进入时,GUI 冻结并且 Visual Studio 报告内存占用逐渐和快速增加,我真的不明白,同时没有抛出异常。

如果我注释掉调用 GUI 更新方法的代码,也会发生这种行为

pressureChartUpdate(linenumber, elapsed);
imuChartUpdate(linenumber + 1, elapsed);

我已经单独测试了解析器,所以我认为问题出在多线程操作上。谁能帮帮我?

一个问题是在 UI 线程上调用 Thread.Sleep。根据定义,这将阻止您的 UI 并使其无响应。一旦进入休眠状态,它就无法执行任何操作。