后台线程如何挂起UI线程?

时间:2009-04-30 01:00:06

标签: c# winforms multithreading

我正在使用后台线程通过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 个答案:

答案 0 :(得分:3)

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

您可以通过查看调试器中挂起的UI线程的callstack来验证这是真的。

答案 1 :(得分:2)

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

如果情况确实如此,那么在新的,单独的工作线程上移动创建此对象应该可以解决问题。

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

答案 2 :(得分:0)

我建议你在一个单独的方法中包含对meter.open()的调用,并使用表单或父控件上的Invoke()或BeginInvoke()构造从updateMeter()方法中调用该方法。这样做会将操作封送回UI线程,并且应该正常执行。我希望这会有所帮助。

答案 3 :(得分:0)

考虑使用BackgroundWorker完成此任务。