5

I have a program that uses the console and GUI for quite important aspects of my program. I presume that these two parts both use the same thread.

The issue is that I'm using a multimeter with an output, and to receive bits of data from it the program sends commands to do it - it uses SCPI, these commands run through the console.

The issue is, whenever I send a command to the multimeter it makes the program become unresponsive until it has received the data back, I know why and I also know how to fix it, but I'm wondering if there is a better way.

Currently I'm changing the default thread that the GUI runs on:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Thread applicationThread = new Thread(() => Application.Run(new Form1()));
    applicationThread.SetApartmentState(ApartmentState.STA);
    applicationThread.Start();
}

This stops the program becoming unresponsive when I send commands to the meter, but I'm not 100% sure if this will create any other issues I've yet to see?

My questions are:

  • Is there a better way to change the thread that the GUI runs on?
  • If not, will this method create any issues I've yet to see?
  • Could I change the Console thread instead?
Johnathan Brown
  • 713
  • 12
  • 35
  • The code in the question will spawn the thread then immediately return, terminating the process. I assume you have more code in the actual project? – Lasse V. Karlsen Aug 10 '15 at 08:42
  • Of course yes, that is just the `program.cs` file which is used to launch the actual program. – Johnathan Brown Aug 10 '15 at 08:44
  • 2
    I think we need to see more code. Why don't you put the communication with your multimeter in a separate thread instead of the UI? – Patrick Hofman Aug 10 '15 at 08:44
  • I've tried this before Patrick. I'm using a dll from Keithley Instruments to talk to their device, but as it uses SCPI all the commands run in / out of the console - this can't be changed. So, from my understanding even if I did run the command from a different thread, the end result would still be the command being ran through the console rendering the same issue – Johnathan Brown Aug 10 '15 at 08:44
  • Are you trying to combine a console app and a Windows Forms app? – Patrick Hofman Aug 10 '15 at 08:58
  • More the fact that I have too. The library uses the console to send commands to the multi meter and also receives the data back through the console - this is just how the devices library was developed. – Johnathan Brown Aug 10 '15 at 09:01
  • But mixing the two is not supported I think. – Patrick Hofman Aug 10 '15 at 09:16
  • 1
    May be it's a good idea to use `WCF service` to handle communication between console and winform apps ? – Fabjan Aug 10 '15 at 09:24
  • 1
    That is a very good idea Fabjan... Thank you! You've just given me so many options I completely forgot about! – Johnathan Brown Aug 10 '15 at 09:31
  • Ended up making a class library, no longer have any hanging program and I don't need to launch my program in a different thread. Thanks for the idea @Fabjan – Johnathan Brown Aug 10 '15 at 12:47
  • @JohnathanBrown always welcome :) So what does the trick ? – Fabjan Aug 10 '15 at 12:55

1 Answers1

3
[STAThread]
static void Main()

This is very unwise, you are breaking the STAThread contract. Which stipulates that you must pump a message loop. Application.Run() in a .NET program. You did this correctly for the thread that displays the UI but not for the main thread. The one you presumably use to talk to the meter.

Worst problem is that it will easily look like you'll get away with it. But it is a ticking time-bomb that's ready to blow up in your face at any time. Misbehavior ranges from arbitrary deadlock, particularly the nasty kind that makes the finalizer thread of a .NET program hang. Happens when the CLR tries to release the COM interop wrapper. Very hard to diagnose, your program ultimately falls over when it runs out of memory. Takes a while, invariably longer than your patience testing the app. To random misbehavior of the meter object itself, usually diagnosed by a call on the object deadlocking or the object not raising an expected event.

The finalizer thread deadlock is certainly the worst problem, bad enough to force you to change this. Focus on the real issue, it is the meter code that's misbehaving. Give it a safe haven by itself, a properly constructed STA thread that pumps. You'll find boiler-plate code in this post. Or just change the attribute to [MTAThread], that forces COM to provide a safe haven for the COM object by itself. But best to take the bull by its horn so you know what's going on instead of relying on undebuggable black magic.

I'd also strongly recommend a support call to the vendor or author of this component. Apartment-threaded COM servers should not behave this way. Something is out of whack.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks for the response Hans. I've actually changed the `program.cs` so that is pumps a message code - `Application.Run(new Form1());`. I've made a class library which now keeps all the multimeter functions in a nice location - this has also seemed to stop the program hang. – Johnathan Brown Aug 10 '15 at 13:37