1

I have a c# .NET multi-threaded application that is freezing the interface. What is unusual about this is that the interface does not freeze unless I let the system sit idle long enough for the screen saver to start (which requires me to reenter my password to re-gain access to the system). When the interface becomes visible again (after I have successfully entered my password) the interface is locked up. As long as I don't let the screensaver start, then the interface does not lockup.

I should point out that I have two different executables that access the same dll and this problem is occurring no matter which application I use to access the DLL. This seems to imply that the problem is in the DLL as the two applications are completely different (C++/MFC) and (C#/.NET) apart from how they relate to the DLL.

Both exes perform similar steps in how they interact with the DLL. They make calls into the dll to setup the serial port communication, open a status window in the DLL, start a thread in the DLL to monitor the comm port, and then starts a thread in the main app that monitors a stack in the dll.

When data is obtained from the comm port by the thread in the DLL, it is parsed and its results are placed on the stack and then posted to the status window via a delegate. When the thread in the exe sees data in the stack, it outputs the data in the main window, also using a delegate.

I found that if I add code to the thread inside the DLL so it calls Application.DoEvents() every 30 seconds, the interface will be frozen for about 30 seconds and then resume activity like normal. I figure something is blocking the main thread and forcing DoEvents() to fire seems to break the lock, but I have no idea what might be causing this lock.

This issue occurs both on my development machine and on a test machine.

I have tried completely removing the output of data to the status window inside the DLL, but that didn't make any difference.

I have been doing multi-threaded programming for years and never seen anything like this; so any advice would be greatly appreciated.

Thanks.

naveen
  • 53,448
  • 46
  • 161
  • 251
PhilGyro
  • 31
  • 1
  • 5

3 Answers3

6

This is a problem that's commonly induced by the SystemEvents class when you have a non-standard way to initialize your user interface. Using threads, specifically. Start your program, Debug + Break All, Debug + Windows + Threads. If you see a thread named ".NET SystemEvents" then you're pretty much guaranteed to get this hang.

Some background: the SystemEvent class supports both console mode apps and GUI apps. For the latter, it should fire its event handlers on the UI thread. The very first time one of its events is subscribed, it creates a little invisible helper window to get the system notifications. It can do this two ways, either by creating the window on the calling thread or by starting up a helper thread. It makes the decision based on the value of Thread.GetApartmentState(). If it is STA then it can create the window on the calling thread and all event callbacks can be properly marshaled to that thread.

This goes wrong if the first window you create is not created on the UI thread. A splash screen for example. That window may contain controls that are interested in a system event like UserPreferenceChanged so they can properly repaint themselves. It now uses the helper thread and any event will be fired from that helper thread, not the UI thread. Poison to any window that runs on the UI thread. The session switch out of a locked workstation (including the screen saver) is for some mysterious reason very likely to cause deadlock. You may also see an occasional painting mishap, the less nasty result of using windows from the wrong thread.

Short from fixing the initialization order, a workaround is to put this in your Main() method, before any windows are created:

Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I can add this easily enough to the c#/.NET app that calls this DLL, but what do I do for the C++/MFC application that calls this DLL? – PhilGyro Jan 11 '11 at 17:36
  • Erm, call an initialization function? Does the C++ code correctly initialize the thread (CoInitializeEx to select STA)? You'd better check Thread.CurrentThread.GetApartmentState() in that init function. – Hans Passant Jan 11 '11 at 17:42
  • I checked the Current Thread's Apartment state when I first enter the DLL and it is set for STA. I also added the line you recommended above to the main method of my C# exe before the Application.Run() and it didn't make any difference. When I start my exe, I open the main form's window and then when the user clicks a button, the call is made to the DLL to open the com port and start the thread. When the user selects the mode to execute, the exe makes another call into the DLL which opens a status window and then alerts the thread in the dll to start collecting data. – PhilGyro Jan 11 '11 at 19:04
  • Are you properly using BeginInvoke() in the DataReceived event handler? – Hans Passant Jan 11 '11 at 19:20
  • What is a DataReceived event handler? I use BeginInvoke in all my calls to the windows from worker threads. – PhilGyro Jan 11 '11 at 20:14
  • Going back to your initial answer. I do see the .NET SystemEvents thread when I break into the code while it is running. Should I not be seeing this at all if I initialize everything correctly. – PhilGyro Jan 11 '11 at 20:17
  • 1
    Well, that's your problem, that *will* deadlock your program. I can't see your code, hard to diagnose the reason. Override the OnHandleCreated method in your form(s) and set a breakpoint on it so you can see what thread they are created on. Use that same debugging window. – Hans Passant Jan 11 '11 at 20:21
  • I have to leave before I'll get a chance to check that. But if I make a call to the DLL from a button on the exe main form and create a window from that function called by the exe, won't that create the window on the main thread? – PhilGyro Jan 11 '11 at 20:24
  • I don't see an OnHandleCreate method in the list of c# properties to overload. – PhilGyro Jan 11 '11 at 20:30
  • Type "protected override" and the intellisense list pops up. – Hans Passant Jan 11 '11 at 20:34
  • One other thing. I originally wrote this in .net 1.1 and had to use an ActiveX control for my serial port communication. To s do this I added it to a form and then initialize the form from my worker thread. Is it possible that this is causing the problem? I don't display this form or anything, just execute this code; try { toolcomm = new CommForm(); } catch(Exception e) { Trace.WriteLine(e.Message); } toolcomm.ShowWnd(); toolcomm.HideWnd(); Where ShowWnd is using BeginInvoked to create the window. Thanks for help. – PhilGyro Jan 11 '11 at 20:35
  • I create a brand new form-based app, launch it, and then break all, go to the thread window and the .NET SystemEvents thread is there. Are you sure this shouldn't exist? – PhilGyro Jan 12 '11 at 14:41
  • Project + Properties, Debug, untick the hosting process option. Which is the way you're running when your main program is MFC. – Hans Passant Jan 12 '11 at 15:00
0

The problem does appear to be related to the ActiveX control is was probably using incorrectly in a form. I switched to using the serial port library in .NET and have not been able to reproduce my problem. Thanks to everyone, especially Hans for their assistance.

PhilGyro
  • 31
  • 1
  • 5
0

I am having the same issue as my PC just hangs up when the screen saver kicks off or I lock my PC and monitor goes to sleep. I am 95% sure that there are deadlocks appearing in my multithreaded app. Look and identify whether there are any deadlocks in your code.

Azhar Khorasany
  • 2,712
  • 16
  • 20