2010-03-01 12 views
16

Me gustaría iniciar x número de hilos desde mi aplicación .NET, y me gustaría hacer un seguimiento de ellos ya que tendré que terminarlos manualmente o cuando mi aplicación cierra mi aplicación más adelante.Iniciando múltiples hilos y haciendo un seguimiento de ellos desde mi aplicación .NET

Ejemplo ==> Entrada de rosca Alfa, Beta comienzo de la rosca .. entonces en cualquier punto en mi solicitud que debería ser capaz de decir Terminar rosca Beta ..

¿Cuál es la mejor manera de realizar un seguimiento de las discusiones abiertas en .NET y ¿qué necesito saber (una identificación?) sobre un hilo para terminarlo? Código de ejemplo, tutorial sería útil.

Respuesta

14

Usted podría ahorrarse el trabajo pesado y utilizar este Smart Thread Pool. Proporciona un sistema de unidad de trabajo que le permite consultar el estado de cada hilo en cualquier punto y terminarlo.

Si eso es demasiado molesto, entonces como se menciona un IDictionary<string,Thread> es probablemente la solución más simple.O aún más simple es dar a cada uno de su hilo de un nombre, y el uso de un IList<Thread>:

public class MyThreadPool 
{ 
    private IList<Thread> _threads; 
    private readonly int MAX_THREADS = 25; 

    public MyThreadPool() 
    { 
     _threads = new List<Thread>(); 
    } 

    public void LaunchThreads() 
    { 
     for (int i = 0; i < MAX_THREADS;i++) 
     { 
      Thread thread = new Thread(ThreadEntry); 
      thread.IsBackground = true; 
      thread.Name = string.Format("MyThread{0}",i); 

      _threads.Add(thread); 
      thread.Start(); 
     } 
    } 

    public void KillThread(int index) 
    { 
     string id = string.Format("MyThread{0}",index); 
     foreach (Thread thread in _threads) 
     { 
      if (thread.Name == id) 
       thread.Abort(); 
     } 
    } 

    void ThreadEntry() 
    { 

    } 
} 

Por supuesto, puede conseguir mucho más implicado y complicado con él. Si matar tus hilos no es sensible al tiempo (por ejemplo, si no necesitas matar un hilo en 3 segundos en una UI) entonces un Thread.Join() es una mejor práctica.

Y si aún no lo ha leído, entonces Jon Skeet tiene this good discussion and solution para el consejo de "no usar abortar" que es común en SO.

+0

Tengo una pregunta, en el Void ThreadEntry(), una vez que creamos un múltiplo de hilos en la aplicación principal del punto de inicio de la secuencia, podemos iniciar cualquier otra aplicación en ese hilo de acuerdo con el número de subprocesos u asignados. – shawn

1

Depende de lo sofisticado que necesite. Podrías implementar tu propio tipo de ThreadPool con métodos de ayuda, etc. Sin embargo, creo que es tan simple como mantener una lista/matriz y agregar/eliminar los hilos a/de la colección en consecuencia.

También podría usar una colección de diccionarios y usar su propio tipo de clave particular para recuperarlos, es decir, Guids/strings.

2

Después de crear su hilo, puede establecer su propiedad Nombre. Suponiendo que lo guarde en alguna colección se puede acceder a él a través de LINQ convenientemente con el fin de recuperar (y abortar) que:

var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault(); 
if(myThread != null) 
    myThread.Abort(); 
1

Vaya, hay tantas respuestas ..

  1. Usted puede simplemente utilizar una matriz para contener los subprocesos, esto solo funcionará si el acceso a la matriz será sequantial, pero si tendrá otro subproceso que acceda a esta matriz, necesitará sincronizar el acceso
  2. Puede usar el grupo de subprocesos, pero el grupo de subprocesos es muy limitado y solo puede contener una cantidad fija de subprocesos.
  3. Como se mencionó anteriormente, puede crear su propio grupo de subprocesos, que en .NET v4 se vuelve mucho más fácil con la introducción de colecciones seguras.
  4. puede gestionarlos sosteniendo una lista de objeto mutex que determinará cuándo deben terminar esos subprocesos, los hilos consultarán el mutex cada vez que se ejecuten antes de hacer cualquier otra cosa, y si se establece, terminará, puede administrar los silenciados desde cualquier lugar, y como mutex son por defenition thread-safe, es bastante fácil ...

puedo pensar en otras 10 formas, pero parece que funcionan. avíseme si no se ajustan a sus necesidades.

3

Se puede crear un diccionario de hilos y asignarles de identificación, como:

Dictionary<string, Thread> threads = new Dictionary<string, Thread>(); 
for(int i = 0 ;i < numOfThreads;i++) 
{ 
    Thread thread = new Thread(new ThreadStart(MethodToExe)); 
    thread.Name = threadName; //Any name you want to assign 
    thread.Start(); //If you wish to start them straight away and call MethodToExe 
    threads.Add(id, thread); 
} 

Si no desea guardar los hilos en contra de un Id se puede usar una lista y luego simplemente enumerar para matar trapos.

Y cuando desee terminarlos, puede cancelarlos. Es mejor tener alguna condición en tu MethodToExe que permita que ese método se vaya, permitiendo que el hilo termine con elegancia. Algo así como:

void MethodToExe() 
{ 
    while(_isRunning) 
    { 
     //you code here// 
     if(!_isRunning) 
     { 
      break; 
     } 
     //you code here// 
    } 
} 

para abortar se puede enumerar el diccionario y llamar Thread.Abort().Estar listo para atrapar ThreadAbortException

+0

@ cornerback84 No recomendaría el uso de Thread.Abort() ... es mejor configurar el hilo en segundo plano. – Kiril

+0

Sí, pero simplemente estaba mostrando cómo hacerlo. Por eso le sugerí que tenga alguna condición en la que pueda abortar el hilo. Puede ser eso, o cualquier excepción como SocketException en la que uno puede salir del methdo – ata

3

pregunté a preguntas similares y recibió un montón de buenas respuestas: Shutting down a multithreaded application

Nota: mi pregunta no requería una salida elegante, pero la gente todavía me recomendó que con gracia salida del bucle de cada hilo.

Lo principal a recordar es que si se quiere evitar que sus hilos impiden que el proceso de terminación se debe configurar todos los hilos a fondo:

Thread thread = new Thread(new ThreadStart(testObject.RunLoop)); 
thread.IsBackground = true; 
thread.start(); 

La mejor forma de iniciar y administrar hilos es en a ThreadPool, pero casi cualquier contenedor puede usarse para mantener una referencia a sus hilos. Sus hilos siempre deben tener una bandera que les diga que terminen y deben revisarlo continuamente.

Además, para un mejor control puede suministrar sus hilos con un CountdownLatch: cada vez que un hilo sale de su ciclo, se emitirá una señal en un CountdownLatch. Su hilo principal llamará al método CountdownLatch.Wait() y se bloqueará hasta que todos los hilos se hayan señalizado ... esto le permite una limpieza adecuada y asegura que todos sus hilos se hayan apagado antes de comenzar la limpieza.

public class CountdownLatch 
{ 
    private int m_remain; 
    private EventWaitHandle m_event; 

    public CountdownLatch(int count) 
    { 
     Reset(count); 
    } 

    public void Reset(int count) 
    { 
     if (count < 0) 
      throw new ArgumentOutOfRangeException(); 
     m_remain = count; 
     m_event = new ManualResetEvent(false); 
     if (m_remain == 0) 
     { 
      m_event.Set(); 
     } 
    } 

    public void Signal() 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref m_remain) == 0) 
      m_event.Set(); 
    } 

    public void Wait() 
    { 
     m_event.WaitOne(); 
    } 
} 

También es digno de mencionar que el método Thread.Abort() hace algunas cosas extrañas:

Cuando llama un hilo Abortar sobre sí misma, el efecto es similar a lanzar una excepción ; la excepción ThreadAbortException ocurre inmediatamente y el resultado es predecible. Sin embargo, si un hilo llama Abort en otro hilo, el aborto interrumpe el código que esté ejecutando . También existe la posibilidad de que un constructor estático se pueda cancelar. En casos excepcionales, esto podría evitar que las instancias de esa clase sean creadas en ese dominio de aplicación. En .NET Framework versiones 1.0 y 1.1, existe la posibilidad de que el hilo pueda abortar mientras se ejecuta finalmente un bloque , en cuyo caso el bloque finalmente se cancela.

El subproceso que llama Abort podría bloque si el hilo que está siendo abortado está en una región protegida de código, tal como un bloque de captura, finalmente bloque, o constreñido región ejecución . Si el hilo que llama Abort contiene un bloqueo que requiere el hilo abortado , puede producirse un interbloqueo.

1

Al iniciar cada hilo, coloque su ManagedThreadId en un diccionario como la clave y la instancia de hilo como el valor. Utilice una devolución de llamada de cada hilo para devolver su ManagedThreadId, que puede usar para eliminar el hilo del Dictionary cuando finaliza. También puede recorrer el diccionario para abortar los hilos si es necesario. Cree los subprocesos de fondo para que finalicen si la aplicación finaliza inesperadamente.

Puede usar una devolución de llamada por separado para indicar que los hilos continúan o se detienen, lo que refleja un indicador establecido por su UI, para una salida elegante. También debe atrapar la excepción ThreadAbortException en sus hilos para que pueda hacer cualquier limpieza si tiene que abortar los hilos en su lugar.

Cuestiones relacionadas