.NET 4.0 and the dreaded OnUserPreferenceChanged Hang
Asked Answered
B

3

15

I have been plagued with the dreaded OnUserPreferenceChanged Hang that's refered to quite nicely by Ivan Krivyakov, here:

http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html#BeginInvokeDance

I posted a question a while back, when I originally encountered the problem:

Yet another C# Deadlock Debugging Question

I thought I had solved it by removing a Control that was constructed off the UI thread, but after a little while it reappeared (probably never left...).

We've been using .NET 3.5, which I understand uses CLR 2.0. Recently, the applciation has been upgraded to use .NET 4.0 Client Profile / CLR 4.0. In addition, we've upgraded from Infragistics WinForms 10.1 to 10.3. The only other difference is that the previous version is obfuscated... has anyone experienced issues with obfuscation and hanging?

I've had another stab at getting rid of any application hangs once and for all, but unusually, I have not been able to reproduce the hang in the most recent version (using .NET 4.0). The hang is simple to reproduce in the previous version (using .NET 3.5), using Ivan Krivyakov's handy Freezer application (see his article for it), which fires a WM_SETTINGCHANGE message upon request.

It may be me being a little hopeful that the issue has disappeared off it's own accord, but does anyone know if there have been any changes to the CLR from 2.0 to 4.0 that would cause this?

-----------------------------------------------------SOLUTION--------------------------------------------------

So after testing variations of the application e.g. CLR 2.0 + Infragistics 2010.1, CLR 2.0 + Infragistics 2010.3 and CLR 4.0 + Infragistics 2010.1, we believe we've identified the problem to have been an issue with an Infragistics component in WinForms 2010.1 (no hot fixes). We still have yet to reproduce the freeze using either CLR 2.0 or CLR 4.0 with Infragistics 2010.3, instead (and we've gotten pretty good at reproducing this now...).

Bartholomeus answered 2/11, 2010 at 12:55 Comment(1)
new link for I. Krivyakov article: Mysterious HangHandwriting
P
17

a Control that was constructed off the UI thread...

Yes, that is a good way to trigger this problem. The underlying problem is caused by the SystemEvents class, it has the unenviable task of raising its events on the correct thread. The UserPreferenceChanged event is the typical trouble-maker, lots of controls subscribe it so they can repaint themselves when the user changes the desktop theme. A component vendor would not overlook the need for this. Nor do the standard .NET framework controls in the toolbox.

A usually decent way to test for this problem is to lock the workstation (press the Win+L keys), also the way the deadlock is commonly triggered on the user's machine. The switch to the secure desktop tends to trigger the event. With the additional quirks that this never happens when you debug your program and that it has tricky time-related behavior since this tends to happen when nobody is at the machine. Extra hard to debug.

One standard way to get into trouble like this is because of an initialization problem in the program. The very first SystemEvents event that is subscribed causes the SystemEvents class to initialize itself and setup the plumbing that's necessary to receive these notifications and raise their corresponding event. A custom splash screen that does too much (i.e. more than just display a bitmap) and runs on a worker thread that is marked as STA is enough to get this wrong. Something as simple as a ProgressBar is already enough. SystemEvents assumes that the worker thread is the main thread of the program and can now easily generate the events on the wrong thread in the future. There is one good diagnostic for this, if that worker thread is no longer around then that generates a first-chance exception. You can see it in the Output window.

Or you create another UI thread and have forms on both threads. Inevitably one of these forms is always going to get the event on the wrong thread.

The only decent advice is to acknowledge that creating UI on a worker thread is rocket science that Microsoft did not know how to do correctly either. Notable is that the .NET 1.x controls have an event handler that still works correctly when it is called from the wrong thread, it merely call Control.Invalidate(). But that was knowledge that appears to have been lost at 2.0, ToolStrip is a good example. And do not trust a component vendor to get this right, Infragistics in particular does not have a stellar reputation. Don't do it.

Perla answered 2/11, 2010 at 14:14 Comment(7)
Thanks for the refreshing information, Hans! We do have a Splash screen that is created through a seperate call to Application.Run(), which I undestood would give it it's own message pump... as long as we marshall any calls into the splash, it would be safe. Is this incorrect then? I didn't know there was some built-in .NET support for splash screens. I'll have a look.Bartholomeus
Also, do you have any idea why I'm unable to reproduce this hang using an unobfuscated version of the application that uses CLR 4.0?Bartholomeus
Deadlocks are very sensitive to timing. The timing in a release build won't be the same as the debug build. It doesn't sound like you have much of a handle on where this problem is induced. I recommend the workaround I proposed.Perla
Thanks for your help Hans. Our multi-threaded splash screen was a bit messy, but with the help of jmcilhinney's suggested implementation: vbforums.com/showthread.php?p=3896435, it's much cleaner now. It did not resolve the issue however. After trying the latest version of Infragistics with CLR 2.0 still being used, we believe we've established it was a bug in an Infragistics component. I'll post back here if it changes... Thanks for your help anyways, Hans - you've at least helped clear up our code a bit =).Bartholomeus
Hi @HansPassant, sorry to trouble you but I wondered if you could offer any advice to me. I have successfully used a multi-threaded splash screen in WinForms and am now attempting to do the same thing with a WPF application. The problem I have (after an exhaustive search) is the one you describe above - I am launching my splash (successfully) on a background STA thread, then attempting to load the main window. This is causing the problem I outline here...Mohican
Would you be able to offer any advice on a way around this without having to revert to WPF default static splash screen. The entire point is that this application is large and uses MEF composition, so the initialization takes some time - I want to show the user what is going on.Mohican
Just to confirm that any UI, even not related to a form that invokes background thread (like custom form for example), is causing application to hang. In my case I have showing a dialog for picking some value that is later used to do a batch job, all within background thread. I notice this in Remote Desktop sessions when every time a session is broken, application would freeze. After relocating dialog from the thread everything worked perfectly. Conclusion: Forget about any UI in background thread. Btw I am on .Net 4.6.1.Purism
M
2

The best guide I've found for resolving this issue is here:

It walks you through using WinDbg to verify the cause of the error and shows you how to find what's causing it. As you mentioned it is most likely caused be a control being created on a non ui thread.

In my case I resolved the issue by creating a factory that uses the SynchronizationContext from the UI thread to create the control and then I call CreateControl() in order to force the creation of a UI handle.

The Microsoft Support article is here:

Mola answered 22/5, 2014 at 21:25 Comment(1)
another good link from support article: learn.microsoft.com/en-us/archive/blogs/dsui_team/…Arrowhead
R
0

If you run the sample app from his webpage with first CLR 2.0 and then CLR 4.0 then you will notice that the problem seems really to be gone in 4.0 - No idea what has been changed, but maybe they really addressed the problem. BR

Roentgenotherapy answered 1/7, 2015 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.