2010-11-02 17 views
9

He estado plagado con el temido OnUserPreferenceChanged Cuelgue que se refirió a bastante bien por Ivan Krivyakov, aquí:NET 4.0 y la temida OnUserPreferenceChanged Cuelgue

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

He publicado una pregunta hace un tiempo, cuando originalmente encontrado con el problema:

Yet another C# Deadlock Debugging Question

pensé que había resuelto mediante la eliminación de un control que se construyó el hilo de interfaz de usuario, pero después de un poco whil e reapareció (probablemente nunca se fue ...).

Hemos estado usando .NET 3.5, que entiendo utiliza CLR 2.0. Recientemente, la aplicación se ha actualizado para usar .NET 4.0 Client Profile/CLR 4.0. Además, hemos actualizado de Infragistics WinForms 10.1 a 10.3. La única otra diferencia es que la versión anterior está ofuscada ... ¿Alguien ha tenido problemas con la ofuscación y el ahorcamiento?

He tenido otra puñalada para deshacerme de cualquier aplicación se cuelga de una vez por todas, pero inusualmente, no he podido reproducir el hang en la versión más reciente (usando .NET 4.0). El hang es simple de reproducir en la versión anterior (usando .NET 3.5), utilizando la práctica aplicación Freezer de Ivan Krivyakov (ver su artículo), que dispara un mensaje WM_SETTINGCHANGE a petición.

Puede que tenga un poco de esperanza de que el problema haya desaparecido por voluntad propia, pero ¿alguien sabe si ha habido algún cambio en el CLR de 2.0 a 4.0 que podría causar esto?

--------------------------------------------- --------SOLUCIÓN----------------------------------------- ---------

Luego de probar las variaciones de la aplicación, por ejemplo CLR 2.0 + Infragistics 2010.1, CLR 2.0 + Infragistics 2010.3 y CLR 4.0 + Infragistics 2010.1, creemos que hemos identificado el problema de haber sido un problema con un componente de Infragistics en WinForms 2010.1 (sin correcciones). Todavía tenemos que reproducir la congelación utilizando CLR 2.0 o CLR 4.0 con Infragistics 2010.3, en su lugar (y hemos conseguido bastante buenos reproductores ahora ...).

+0

nuevo enlace para I. Krivyakov artículo: [Mysterious Hang] (http://www.ikriv.com/dev/dotnet/MysteriousHang.html) – tibx

Respuesta

15

un control que se construyó el hilo UI ...

Sí, es una buena manera de desencadenar este problema. El problema subyacente es causado por la clase SystemEvents, tiene la tarea poco envidiable de elevar sus eventos en el hilo correcto. El evento UserPreferenceChanged es el típico alborotador, muchos controles lo suscriben para que puedan volver a pintarse cuando el usuario cambie el tema del escritorio. Un proveedor de componentes no pasaría por alto la necesidad de esto. Tampoco lo hacen los controles estándar de .NET Framework en la caja de herramientas.

Una forma generalmente decente para probar este problema es bloquear la estación de trabajo (presione las teclas Win + L), también la forma en que el interbloqueo se activa comúnmente en la máquina del usuario. El cambio al escritorio seguro tiende a desencadenar el evento. Con las peculiaridades adicionales de que esto nunca ocurre cuando se depura el programa y tiene un comportamiento complicado relacionado con el tiempo, ya que esto suele ocurrir cuando nadie está en la máquina. Extra difícil de depurar.

Una forma estándar de tener problemas como este es debido a un problema de inicialización en el programa.El primer evento SystemEvents que se suscribe hace que la clase SystemEvents se inicialice a sí misma y configure la plomería necesaria para recibir estas notificaciones y generar su evento correspondiente. Una pantalla de bienvenida personalizada que hace demasiado (es decir, más que solo mostrar un mapa de bits) y se ejecuta en un subproceso de trabajo que está marcado como STA es suficiente para hacer esto mal. Algo tan simple como una ProgressBar ya es suficiente. SystemEvents asume que el hilo de trabajo es el hilo principal del programa y ahora puede generar fácilmente los eventos en el hilo incorrecto en el futuro. Hay un buen diagnóstico para esto, si ese hilo de trabajo ya no existe entonces eso genera una excepción de primera oportunidad. Puedes verlo en la ventana de Salida.

O bien, crea otro subproceso de interfaz de usuario y tiene formularios en ambos subprocesos. Inevitablemente, una de estas formas siempre tendrá el evento en el hilo equivocado.

El único consejo decente es reconocer que la creación de IU en un hilo de trabajo es una ciencia revolucionaria que Microsoft tampoco sabía cómo hacer correctamente. Es notable que los controles .NET 1.x tienen un controlador de eventos que aún funciona correctamente cuando se llama desde el hilo equivocado, simplemente llama a Control.Invalidate(). Pero ese fue el conocimiento que parece haberse perdido en 2.0, ToolStrip es un good example. Y no confíe en que un proveedor de componentes lo haga bien, Infragistics, en particular, no tiene una reputación estelar. No lo hagas

+0

Gracias por la información refrescante, Hans! Tenemos una pantalla de Splash que se crea a través de una llamada separada a Application.Run(), lo que no entendí le daría su propia bomba de mensajes ... siempre que marquemos cualquier llamada en el splash, sería seguro. ¿Es esto incorrecto entonces? No sabía que había alguna compatibilidad con .NET incorporada para pantallas de presentación. Le echaré un vistazo. – Roo

+0

Además, ¿tiene alguna idea de por qué no puedo reproducir este bloqueo utilizando una versión no difusa de la aplicación que utiliza CLR 4.0? – Roo

+0

Los bloqueos son * muy * sensibles al tiempo. El tiempo en una compilación de lanzamiento no será el mismo que la compilación de depuración. No parece que tengas un buen conocimiento de dónde se induce este problema. Recomiendo la solución alternativa que propuse. –

1

La mejor guía que he encontrado para resolver este problema es aquí:

Se le guía a través del uso de WinDbg para verificar la causa del error y le muestra cómo encontrar lo que lo está causando Como mencionaste, lo más probable es que se deba a que se haya creado un control en un hilo que no sea de la interfaz de usuario.

En mi caso resolví el problema creando una fábrica que usa el SynchronizationContext del subproceso UI para crear el control y luego llamo CreateControl() para forzar la creación de un identificador de UI.

El artículo de soporte de Microsoft está aquí:

0

Si ejecuta la aplicación de ejemplo de su página web con la primera CLR 2.0 y luego CLR 4.0, entonces se dará cuenta de que el problema parece realmente estar fuera en 4.0 - No tengo idea de qué se ha cambiado, pero tal vez realmente abordaron el problema. BR