¿Cómo parar los hilos?

Hola chicos, empiezo hilos con tal código:

Thread[] thr; private void button1_Click(object sender, EventArgs e) { decimal value = numericUpDown2.Value; int i = 0; threads_count = (int)(value); thr = new Thread[threads_count]; for (; i < threads_count; i++) { thr[i] = new Thread(new ThreadStart(go)); thr[i].IsBackground = true; thr[i].Start(); } } 

Cómo detenerlos a todos si mi condición se hace realidad.

Una serie de respuestas dicen abortar el hilo. Nunca aborte un hilo a menos que sea una situación de emergencia y esté cerrando la aplicación .

El CLR garantiza que sus estructuras de datos internas no están dañadas por un aborto de subproceso. Esta es la única (*) garantía hecha por el CLR con respecto a los abortos de hilos . Específicamente no garantiza:

  • Que el hilo en realidad abortará. Los hilos pueden endurecerse contra la terminación.
  • Que cualquier estructura de datos que no esté en el CLR en sí no será corrompida. La anulación de subprocesos en medio de operaciones cruciales puede dejar las estructuras de datos BCL o las estructuras de datos del usuario en estados arbitrariamente inconsistentes. Esto puede bloquear su proceso misteriosamente más tarde.
  • Que se cerrarán las cerraduras. Los hilos que se abortan pueden hacer que los lockings se mantengan para siempre, pueden causar interlockings, etc.

En caso de que no esté siendo claro: es increíblemente peligroso abortar un hilo y solo debes hacerlo cuando todas las alternativas sean peores.

Entonces, ¿qué sucede si desea iniciar un hilo y luego apagarlo de forma limpia?

Primero, no hagas eso. No comience un hilo en primer lugar. Inicie una Task con un token de cancelación y cuando desee apagarla, señale su token de cancelación.

Si tiene que iniciar un hilo, entonces comience el hilo tal que haya algún mecanismo por el cual el hilo principal y el hilo de trabajo puedan comunicarse de forma limpia y segura “Quiero que se cierre de manera limpia en este momento”.

Si no sabe cómo hacerlo, deje de escribir código de multiproceso hasta que aprenda a hacerlo.


(*) Esta es una pequeña mentira; El CLR también ofrece ciertas garantías con respecto a las interacciones de los abortos de subprocesos y las regiones de códigos especiales, como las regiones de ejecución restringida y, finalmente, los bloques.

Puede usar un CancellationToken para indicar cuándo debe detenerse la operación.

  1. Cree un campo CancellationTokenSource como un campo de instancia de su tipo que inicialice en el controlador de clic de botón.

  2. En su método en segundo plano, verifique periódicamente la propiedad IsCancellationRequested del Token en el origen del token, o llame a ThrowIfCancellationRequested() si desea que solo lance una excepción si se cancela.

  3. Cuando quieras detener los hilos, llama a Cancel en la fuente del token.

Modo brutal (no recomendado): use el método Thread.Abort para abortar hilos. Este método genera ThreadAbortException en el hilo. Me gusta esto:

 foreach(Thread thread in thr) thread.Abort(); 

Pero una mejor manera es notificar el hilo sobre la cancelación y dejar que termine correctamente su trabajo. Puedes hacerlo simplemente con tareas de .Net 4:

 Task[] thr = new Task[threads_count]; var source = new CancellationTokenSource(); for (int i = 0; i < threads_count; i++) { thr[i] = Task.Factory.StartNew(go, source.Token); } // later, when condition is met source.Cancel(); 

Y aquí es cómo debe verse la cancelación:

 private static void go(object obj) { CancellationToken token = (CancellationToken)obj; while (true) { if (token.IsCancellationRequested) return; // do some work } } 

Si desea saber cómo terminar el hilo con gracia, le recomiendo que consulte el siguiente ejemplo en MSDN :

 using System; using System.Threading; public class Worker { public void DoWork() { while (!_shouldStop) { Console.WriteLine("worker thread: working..."); } Console.WriteLine("worker thread: terminating gracefully."); } public void RequestStop() { _shouldStop = true; } // Volatile is used as hint to the compiler that this data // member will be accessed by multiple threads. private volatile bool _shouldStop; } public class WorkerThreadExample { static void Main() { Worker workerObject = new Worker(); Thread workerThread = new Thread(workerObject.DoWork); workerThread.Start(); Console.WriteLine("main thread: Starting worker thread..."); while (!workerThread.IsAlive); // Loop until worker thread activates // Put the main thread to sleep for 1 millisecond to // allow the worker thread to do some work: Thread.Sleep(1); workerObject.RequestStop(); // Use the Join method to block the current thread // until the object's thread terminates. workerThread.Join(); Console.WriteLine("main thread: Worker thread has terminated."); } } 

Este es el código de formulario de Windows en el que:

  • 1) Al hacer clic en el botón de inicio, el hilo principal crea otro hilo
  • 2) Nuevamente creado el hilo crea en más hilo.
  • 3) Al hacer clic en el botón Detener, primero debe finalizar el último hilo. Luego, debe finalizar el hilo creado por el hilo principal.

     namespace Thread_TerminateProblem { public partial class Form1 : Form { private static AutoResetEvent m_ResetEvent = null; private static ManualResetEvent m_ResetEvent_Thread = new ManualResetEvent(false); enum ServiceState { Start, Stop }; bool flag = false; int x = 0; ServiceState _state; public Form1() { InitializeComponent(); } private void btnStart_Click(object sender, EventArgs e) { flag = true; _state = ServiceState.Start; m_ResetEvent = new AutoResetEvent(true); Thread t1 = new Thread(fun_Thread1); t1.Start(); t1.Name = "Thread1"; } private void btnStop_Click(object sender, EventArgs e) { _state = ServiceState.Stop; m_ResetEvent.Set(); } private void fun_Thread1() { while (true) { m_ResetEvent.WaitOne(); switch (_state) { case ServiceState.Start: { Thread t = new Thread(fun_Thread2); t.Start(); t.Name = "Thread2"; break; } case ServiceState.Stop: { m_ResetEvent_Thread.Set(); flag = true; break; } } // When the child Thread terminates, Then only this thread should terminate if (flag == true) { // Waiting for notification from child Thread notifyParent.WaitOne(); Thread.Sleep(100); break; } m_ResetEvent.Reset(); } } private static ManualResetEvent notifyParent = new ManualResetEvent(false); private void fun_Thread2() { while (true) { if (m_ResetEvent_Thread.WaitOne(1, false)) { notifyParent.Set(); break; } x++; } } } 

    }

La respuesta simplista es utilizar el método Abort () de subproceso, sin embargo, su código no deja claro qué condición,

¿Qué pruebas de bucle contra una condición? ¿Por qué necesitas abortar un hilo? Estoy preguntando ya que puede haber una mejor manera de abordar esto