一个后台线程如何导致UI线程挂起?

5

我正在使用一个后台线程通过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.
            }
        }
    }
}

编辑:可能不太清楚我想表达的意思。我应该说“卡顿短暂地停止运行”。

4个回答

3

仪表需要在STA中运行吗?调用Open()是否因此被编组回UI线程?

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


UI 仅会冻结一秒钟,我不知道如何在这种情况下在调试器中断点。但是你给了我一个想法,将 'new FancyVoltmeter()' 行放在线程处理程序 'UpdateMeter' 中。UI 不再冻结,这非常有趣。 - P a u l

2

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

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

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


0
我建议你将调用meter.open()的部分封装成一个独立方法,并在updateMeter()方法中使用Invoke()或BeginInvoke()结构从表单或父控件中调用该方法。这样做将把操作传递回UI线程,并且应该可以顺利执行。希望这能帮到你。

我刚试了一下,但在Open调用期间它仍然会冻结主窗口。我尝试了MethodInvoker: var hwnd = Process.GetCurrentProcess().MainWindowHandle; mainWnd = Control.FromHandle(hwnd); if(mainWnd != null) mainWnd.Invoke(method); - P a u l
这难道不会更或多或少地保证问题中试图避免的确切行为吗?如果打开调用需要一段时间并被强制在 UI 线程上执行,那么 UI 在此期间肯定会处于无响应状态。 - Fredrik Mörk

0
考虑使用 BackgroundWorker 来完成这个任务。

我之前尝试过使用BackgroundWorker,但是当调用Open时应用程序仍然会偶尔冻结。目前来说,在工作线程中实例化ActiveX控件是唯一有效的方法。 - P a u l

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接