views:

713

answers:

5

I am using a background thread to initialize an instrument over USB. The UI hangs when I try to open the device. I would expect the background thread to pause when calling Open on the device, but not the UI thread. I am testing this with no UI interaction from the background thread. I don't know how to debug the problem, and it's too broad a question, but perhaps someone has seen something like this before. There is nothing wrong with the ActiveX interop as far as I know, the device works correctly. This is the general approach:

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.
            }
        }
    }
}

Edit: Perhaps unclear what I meant. By 'hang' I should say 'freezes momentarily'.

+3  A: 

Does meter require running in an STA? Is the call to Open() actually being marshalled back to the UI thread for this reason?

You can verify this is true by looking at the callstack of the hung UI thread in the debugger.

Michael
The UI freezes only for a second and I don't know how to break in the debugger in this case. But you gave me an idea to put the 'new FancyVoltmeter()' line in the thread handler 'UpdateMeter'. The UI no longer freezes, and this is very interesting.
P a u l
A: 

I would suggest you wrap the call to meter.open() in a separate method, and call that method from within the updateMeter() method using Invoke() or BeginInvoke() construct on the form or parent control. Doing this will marshal the action back on to the UI thread and should execute gracefully. I hope this helps.

James
I just tried this and it still freezes the main window during the Open call. I tried MethodInvoker with this:var hwnd = Process.GetCurrentProcess().MainWindowHandle;mainWnd = Control.FromHandle(hwnd);if(mainWnd != null) mainWnd.Invoke(method);
P a u l
Wouldn't that more or less guarantee the exact behavior that is trying to be avoided in the question? If the Open call takes a while and is forces to execute on the UI thread, surely the UI will stay inresponsive during that time?
Fredrik Mörk
A: 

Consider using a BackgroundWorker for this task.

GregC
I tried BackgroundWorker before and the app still froze up periodically when Open was called. Instantiating the ActiveX control within the worker thread is the only thing that works, so far.
P a u l
+2  A: 

How long time does the instantiation of the FancyVoltmeter take? Could it be that it is not the Open method that causes the UI freeze, but creating the COM object (which is done on the UI thread)?

If that turns out to be the case, moving the creation of this object to happen on the new, separate worker thread should take care of the problem.

Edit: I saw now that you already found this out in your comment to Michael...

Fredrik Mörk
A: 

recode everything. place everything on thread. use the emulator to max out the specs of the device

synchronica