2010-02-22 18 views
8

Estoy intentando escribir una ThreadManager para mi C# aplicación. Creo varios hilos:
Un hilo para mi escritor de texto.
Un hilo que supervisa algunas estadísticas.
múltiples hilos para llevar a cabo una gran secuencia de cálculos (hasta 4 hilos por núcleo y ejecutar mi aplicación en un servidor de cuatro núcleos 2x).El cierre de una aplicación multiproceso

Mi aplicación se ejecuta normalmente durante hasta 24 horas a la vez, por lo que todos los hilos se crean en el principio y que persisten a través de toda la vez que se ejecuta la aplicación.

Quiero tener un solo lugar donde "registrar" todas mis bandas de rodadura y cuando la aplicación se está cerrando, simplemente invoco un método y pasa por todos los hilos registrados y los apaga.

Para ello he ideado la clase siguiente:

public class ThreadManager 
{ 
    private static Object _sync = new Object(); 
    private static ThreadManager _instance = null; 
    private static List<Thread> _threads; 
    private ThreadManager() 
    { 
     _threads = new List<Thread>(); 
    } 

    public static ThreadManager Instance 
    { 
     get 
     { 
      lock (_sync) 
      { 
       if (_instance == null) 
       { 
        _instance = new ThreadManager(); 
       } 
      } 
      return _instance; 
     } 
    } 

    public void AddThread(Thread t) 
    { 
     lock (_sync) 
     { 
      _threads.Add(t); 
     } 
    } 

    public void Shutdown() 
    { 
     lock (_sync) 
     { 
      foreach (Thread t in _threads) 
      { 
       t.Abort(); // does this also abort threads that are currently blocking? 
      } 
     } 
    } 
} 

que quieren asegurarse de que todos mis hilos son matados por lo que la aplicación puede cerrar correctamente y apagar en el medio de algún cálculo es bien también. ¿Debería estar al tanto de algo aquí? ¿Es este enfoque bueno dada mi situación?

+0

¡WOW! Muchas buenas respuestas ... es difícil elegir ahora. Le di la marca a Nate porque era el primero, y sería injusto quitársela. Veamos qué dicen los votos. Obtengo algo útil de todas sus respuestas, así que por favor vote sus corazones. – Kiril

+0

El comportamiento predeterminado de los hilos del grupo de subprocesos es el mismo que el sugerido. Si no te importa que tus hilos no terminen, el mío es la solución más simple. Obviamente, las otras respuestas aportan buenos puntos sobre la administración de hilos, pero específicamente indica que matar hilos en el medio de un cálculo está bien. –

+0

Estoy de acuerdo contigo, Nate;), no te voy a quitar la marca de verificación, porque sería injusto y me dabas la respuesta más precisa, rápida y simple ... Sí quiero que otras personas obtengan su feria crédito, entonces quiero que todos voten por todas las buenas respuestas. – Kiril

Respuesta

16

Si se colocan los hilos a las discusiones de fondo, que serán matados cuando la aplicación se cierra.

myThread.IsBackground = true; 

obviamente, si necesita que los hilos terminen antes del cierre, esta no es la solución que desea.

+0

Gracias Nate, configuro todos mis hilos a los hilos de fondo cuando los creo ... ¿eso significa que no necesito abortarlos? – Kiril

+0

sí, si están configurados en subprocesos de fondo, el cierre de la aplicación forzará la salida de los subprocesos. http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx –

2

El único problema específico que sé de es éste: http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx

Pero yo evitaría tener que recurrir a un diseño como este. Puedes forzar cada uno de tus hilos para que verifiquen con cierta regularidad que es hora de apagarlos, y al apagarlos, configura esa bandera y espera a que todos los hilos terminen (con Join()). Se siente un poco más como un apagado controlado de esa manera.

14

Abortar los hilos es lo que haces cuando todo lo demás falla. Es algo peligroso que solo debes hacer como último recurso. La forma correcta de hacerlo es realizar la lógica de subprocesamiento de manera que cada subproceso de trabajo responda rápida y correctamente cuando el subproceso principal le da el comando de desactivarse.

Coincidentemente, este es el tema de mi blog de esta semana.

http://blogs.msdn.com/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx

+1

que las excepciones hilo abortar se bloquean durante la ejecución de bloques finally es nuevo para mí. Gracias por agregar esto. –

+0

@ fatcat1111: De hecho, nada garantiza que un hilo abortado * nunca * se detenga como resultado del aborto. Simplemente otra razón para evitar Thread.Abort; es peligroso * y * no confiable. –

+0

De acuerdo, definitivamente una opción de último recurso. –

3

¿Qué pasa si AddThread se llama mientras que su apagado está funcionando?

Cuando el cierre finaliza, el hilo que espera en AddThread agregará un nuevo hilo a la colección. Esto podría provocar bloqueos en su aplicación.

Añadir una bandera bool que alguna vez sólo configuró en apagado para proteger contra esto.

bool shouldGoAway = false; 
public void AddThread(Thread t) 
{ 
    lock (_sync) 
    { 
     if(! shouldGoAway) 
      _threads.Add(t); 
    } 
} 

public void Shutdown() 
{ 
    lock (_sync) 
    { 
     shouldGoAway = true; 
     foreach (Thread t in _threads) 
     { 
      t.Abort(); // does this also abort threads that are currently blocking? 
     } 
    } 

Además, no debe usar miembros estáticos, no hay razón para eso ya que tiene su instancia de Singleton.

.Abort() no aborta hilos que están bloqueando en el espacio administrado.Entonces, si haces eso, necesitas usar algún otro mecanismo.

1

Si no se preocupan por el estado subproceso de trabajo, entonces puede recorrer _thread y abortar:

void DieDieDie() 
{ 
    foreach (Thread thread in _thread) 
    { 
     thread.Abort(); 
     thread.Join(); // if you need to wait for the thread to die 
    } 
} 

En su caso probablemente puede abortar a todos y apagado a medida que se acaba de hacer cálculos . Pero si necesita esperar una operación de escritura en la base de datos o necesita cerrar un recurso no administrado, entonces necesita atrapar la excepción ThreadAbortException o señalar los hilos para matarse graciosamente.

0

¿Quieres cancelación hilo diferido, que básicamente significa que los hilos terminan a sí mismos en lugar de un gestor de hilo cancelación de hilos de forma asíncrona, que es mucho más imprecisa y peligrosa.

te deseaba para manejar la cancelación de rosca más elegante que la terminación inmediata, puede utilizar los manejadores de señales que se activan por eventos fuera de la rosca - por su gerente hilo tal vez.

Cuestiones relacionadas