【问题标题】:How can a background thread hang the UI thread?后台线程如何挂掉UI线程?
【发布时间】:2010-07-22 16:30:51
【问题描述】:

我正在使用后台线程通过 USB 初始化仪器。当我尝试打开设备时 UI 挂起。我希望后台线程在设备上调用 Open 时暂停,而不是 UI 线程。我正在测试这个,没有来自后台线程的 UI 交互。我不知道如何调试这个问题,而且这个问题太宽泛了,但也许有人以前见过这样的东西。据我所知,ActiveX 互操作没有任何问题,设备工作正常。这是一般方法:

using System;
using FancyVoltmeterLibrary;

namespace SOQuestion
{
    public class MeterClass
    {
        private FancyVoltmeter meter;
        private Thread meterThread;

        public MeterClass()
        {
            // Create instance of ActiveX/COM object.
            meter = new FancyVoltmeter();

            meterThread = new Thread(UpdateMeter);
            meterThread.Name = "Meter Thread";
            meterThread.Priority = ThreadPriority.Normal;
            meterThread.IsBackground = true;
            meterThread.Start();
        }

        private void UpdateMeter()
        {
            while(true)
            {
                Thread.Sleep(1000);
                if(!meter.IsOpen())
                {
                    // Meter may be powered off here.
                    // The call to Open takes about 1 second. 
                    // UI hangs during the call???
                    meter.Open();
                }
                // code to read meter goes here.
            }
        }
    }
}

编辑:也许不清楚我的意思。通过“挂起”,我应该说“暂时冻结”。

【问题讨论】:

    标签: c# winforms multithreading


    【解决方案1】:

    仪表是否需要在 STA 中运行?出于这个原因,对 Open() 的调用实际上是否被编组回 UI 线程?

    您可以通过查看调试器中挂起的 UI 线程的调用堆栈来验证这一点。

    【讨论】:

    • UI 只冻结了一秒钟,在这种情况下我不知道如何中断调试器。但是您给了我一个想法,将“new FancyVoltmeter()”行放在线程处理程序“UpdateMeter”中。 UI 不再冻结,这很有趣。
    【解决方案2】:

    FancyVoltmeter 的实例化需要多长时间?会不会导致 UI 冻结的不是 Open 方法,而是创建 COM 对象(在 UI 线程上完成)?

    如果是这样的话,将这个对象的创建移动到新的、单独的工作线程上应该可以解决这个问题。

    编辑:我现在看到你已经在对迈克尔的评论中发现了这一点......

    【讨论】:

      【解决方案3】:

      我建议您将对meter.open() 的调用包装在一个单独的方法中,并在表单或父控件上使用Invoke() 或BeginInvoke() 构造从updateMeter() 方法中调用该方法。这样做会将动作编组回 UI 线程,并且应该优雅地执行。我希望这会有所帮助。

      【讨论】:

      • 我刚试过这个,它仍然在 Open 调用期间冻结主窗口。我用这个尝试了 MethodInvoker: var hwnd = Process.GetCurrentProcess().MainWindowHandle; mainWnd = Control.FromHandle(hwnd); if(mainWnd != null) mainWnd.Invoke(method);
      • 这不会或多或少地保证问题中试图避免的确切行为吗?如果 Open 调用需要一段时间并且被强制在 UI 线程上执行,那么 UI 肯定会在那段时间内保持无响应吗?
      【解决方案4】:

      考虑为此任务使用 BackgroundWorker。

      【讨论】:

      • 我之前尝试过 BackgroundWorker,但在调用 Open 时应用程序仍会定期冻结。到目前为止,在工作线程中实例化 ActiveX 控件是唯一可行的方法。
      猜你喜欢
      • 2023-04-05
      • 1970-01-01
      • 2017-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      • 1970-01-01
      相关资源
      最近更新 更多