.net multithreading process appdomain finalizer

.net - ¿Cuál es el alcance del hilo del finalizador, por dominio de aplicación o por proceso?



multithreading process (1)

Parece que de hecho solo hay un hilo por instancia de CLR dentro del proceso, por el momento, de todos modos. Aquí hay un código para mostrar que:

Test.cs:

using System; class Test { static void Main() { AppDomain.CreateDomain("First") .ExecuteAssembly("ShowFinalizerThread.exe"); AppDomain.CreateDomain("Second") .ExecuteAssembly("ShowFinalizerThread.exe"); } }

ShowFinalizerThread.cs:

using System; using System.Threading; class ShowFinalizerThread { static Random rng = new Random(); ~ShowFinalizerThread() { Console.WriteLine("Thread/domain: {0}/{1}", Thread.CurrentThread.ManagedThreadId, AppDomain.CurrentDomain.FriendlyName); if (rng.Next(10) == 0) { Console.WriteLine("Hanging!"); Thread.Sleep(2000); } } static void Main() { new Thread(LoopForever).Start(); } static void LoopForever() { while (true) { new ShowFinalizerThread(); GC.Collect(); GC.WaitForPendingFinalizers(); Thread.Sleep(300); }; } }

Compile cada uno como una aplicación de consola, luego ejecute test.exe (desde la línea de comandos es más fácil, IMO). Verás que el finalizador de un dominio de aplicación bloquea a otro.

En el futuro, no me sorprendería ver un finalizador por núcleo en lugar de por AppDomain, pero parece que todavía tendrás problemas :(

Tienes mi más sentido pésame (aunque no una solución): una vez que encontré un punto muerto en un Blob de Oracle. Pudimos arreglarlo desechándolo de manera adecuada, pero sé que no todo funciona tan bien, ¡y fue realmente doloroso encontrarlo!

Basado en toda mi lectura, debe haber un hilo GC para invocar a todos los finalizadores. Ahora, la pregunta es cuál es el alcance de este hilo "único", por proceso o por dominio de aplicación, ya que toda la intención de los dominios es separar y hacer diferentes aplicaciones "independientes" en un espacio de proceso.

Leí aquí :

Si se produce una excepción no controlada en un finalizador, el hilo de ejecución del CLR se tragará la excepción, tratará el finalizador como si se completara normalmente, lo eliminará de la cola predecible y pasará a la siguiente entrada.

Más serio, sin embargo, es qué pasa si su finalizador no sale por alguna razón, por ejemplo bloquea, esperando una condición que nunca ocurre. En este caso, el hilo del finalizador se colgará, por lo que no se recogerán más objetos finalizables. Debe ser muy consciente de esta situación y atenerse a escribir el código más simple para liberar sus recursos no administrados en finalizadores.

Otra consideración es qué sucede durante el cierre de la aplicación. Cuando el programa se cierra, el recolector de basura intentará llamar a los finalizadores de todos los objetos finalizables, pero con ciertas limitaciones:

  • Los objetos finalizables no se promueven a generaciones de alto montón durante el apagado.

  • Cualquier finalizador individual tendrá un máximo de 2 segundos para ejecutarse; si lleva más tiempo, será eliminado.

  • Hay un máximo de 40 segundos para que se ejecuten todos los finalizadores; si algún finalizador todavía se está ejecutando, o pendiente en este punto, todo el proceso se cancela abruptamente.

Demasiadas publicaciones (e incluso documentación oficial) uso indebido de los términos "aplicación", "proceso" y "dominio de aplicación", la mayoría de ellos incluso suponiendo que son iguales, porque generalmente las aplicaciones se ejecutan en un único dominio de aplicación en un solo proceso . Este mal uso hace que todos estos documentos sean difíciles de leer, y ni siquiera útiles.

Entonces, mi pregunta asume más de una aplicación, cada una se ejecuta en un dominio de aplicación separado en un solo proceso.

¿Todas estas aplicaciones comparten los mismos subprocesos GC y finalizador? ¿El problema descrito en el artículo anterior (suspender el hilo del finalizador) afectará a todas las aplicaciones en ese proceso? En caso afirmativo, ¿hay una solución alternativa (además de no utilizar malas aplicaciones), como para descubrir el hilo del finalizador y enviarlo Thread.Abort?

Todo lo anterior es porque me tocó un problema similar. Mi aplicación se ejecuta en un dominio de aplicación separado como complemento de software de terceros (Outlook). Debido a varias razones, necesito llamar a GC.Collect y GC.WaitForPendingFinalizers para liberar completamente las referencias COM (las rutinas de interoperabilidad habituales no son suficientes para Office / Outlook), cuando se está ejecutando un complemento de terceros en particular, mi GC.WaitForPendingFinalizers se cuelga para siempre , entonces sospecho que hay un finalizador "malo" en el agregado de ese tercero. No tengo control sobre la sustitución / eliminación de esa adición (requisito del cliente), así que tengo que resolver por mi cuenta cómo hacer que coexistan.