【问题标题】:Thread used for Serial port data processing throwing "This BackgroundWorker is currently busy and cannot run multiple tasks concurrently"用于串口数据处理的线程抛出“这个BackgroundWorker当前很忙,不能同时运行多个任务”
【发布时间】:2009-07-28 23:14:03
【问题描述】:

我正在用 C# 开发一个应用程序,它从串行端口获取数据、处理它并将其显示给 UI。 数据在 5-50 毫秒之间的速度非常快。在我没有使用任何线程之前。因此应用程序依赖于从串行端口获取数据、处理数据并将其显示给 UI 的单个 App 线程。它正在丢失一些数据。 然后我开始实现 BackgroundWorker 线程以消除单线程上的一些开销并考虑良好的性能。现在我收到“此 BackgroundWorker 目前很忙,无法同时运行多个任务”错误。我认为 Thread 无法应对来自串行端口的数据的速度。所以在执行“backgroundWorker1.RunWorkerAsync(data);”时抛出错误。我需要一些建议来实现这种场景的更好方法是什么?

【问题讨论】:

标签: c# multithreading serial-port backgroundworker


【解决方案1】:

geofftnz 是正确的,我会为你扩展一点。您应该只启动一次后台工作程序,并让它使用 ReportProgress 将数据反馈给 GUI 线程。工作线程看起来像这样。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackGroundWorker;
    while(!e.CancellationPending)
    {
        ResultObject ro = new ResultObject();  // your own type here, obviously
        //Process and store some data in ro;
        worker.ReportProgress(0, ro);
        //Do not modify ro after reporting progress to avoid threading issues
    }
}

从 GUI 注册到 ProgressChanged 事件,并且只启动一次 worker。

【讨论】:

  • 感谢 Mirozell,这是我正在调用的方法,它通过检查 ro Passed 的值将我的数据发送到 UI。但它以某种方式无法正确处理此功能。当我调试该功能时,它不允许我正确调试它并来回跳转。不知道这里发生了什么。
  • Visual Studio 会自动跳转到任何遇到断点的线程。如果您打开“在源代码中显示线程”,您将获得一些其他线程在哪里的指示。在您的情况下,最简单的事情可能是在调试 gui 线程时删除/禁用工作程序中的断点,反之亦然。
  • 伙计们,我能够解决这个问题。我正在做的是将我从 SerialPort 获得的数据添加到队列中。我正在使用 BackgroundWorker 线程通过检查它的忙碌状态来对队列进行出队。所以不再有任何异常。感谢所有花时间支持我的人。
【解决方案2】:

问题是你在backgroundWorker1.RunWorkerAsync() 完成之前的操作之前调用它。

您可能想要的是一个读取串行端口、缓冲数据并通知主 UI 线程数据可用的单线程。

【讨论】:

  • 感谢您的快速回复。我正在使用单后台工作线程从串行端口读取数据、缓冲数据并通知 UI。我认为 backgroundWorker1_RunWorkerCompleted 事件将通过 if(e.Result != null) {} 通知 UI 线程有一个有效的输出,如果我错了,请纠正我。 - 切坦
  • 查看 Mirozell 的回答 :)
【解决方案3】:

尝试添加它,以确保后台工作人员一次只运行一项工作。

if(!backgroundWorker1.IsBusy)
    backgroundWorker1.RunWorkerAysnc();

您还可以取消当前作业,这是一个代码示例

    private void WhereBackworkerStarts()
    {
        backgroundWorker.WorkerSupportsCancellation = true;

        if (backgroundWorker.IsBusy)
            backgroundWorker.CancelAsync();
        else
            backgroundWorker.RunWorkerAsync();
    }

    // Events
    static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        for(int i = 0; i < int.MaxValue; i++)
        {
            if (backgroundWorker.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            // Do work here
        }
        e.Result = MyResult;
    }

    static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Deal with results
    }

【讨论】:

  • 我已经添加了这个,但是在这种情况下,当这个线程很忙时我会丢失一些数据,我的意思是数据没有被处理并且不会进入 UI。
  • 我正在寻找的方法数据应该是连续流动的。
  • 那么最好的办法是使用线程池,而不是单个 backgroundWorker,因为这些通常用于在后台处理大量数据,并定期更新UI,而 UI 仍然是响应式的
  • 如果我调用 CancelAsync() 它将取消我正在进行的任务。我不想要那个。我希望在不丢失任何数据的情况下处理每个任务。
  • 一个不错的线程池教程switchonthecode.com/tutorials/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多