new - threadpool.queueuserworkitem c#
Llamar a Thread.Abort en un subproceso desde un ThreadPool (5)
El uso de Thread.Abort no se recomienda, ya que puede dejar su aplicación en un estado no válido. La razón de esto es que al exigir que se aborte un subproceso, se puede generar una excepción en casi cualquier lugar posible en esa biblioteca de terceros. Es posible que haya segmentos de código que no estén escritos para poder hacer frente a estos abortos asíncronos.
Entonces, aunque generalmente no se recomienda abortar subprocesos, hay hosts que son muy agresivos en abortar subprocesos. Uno de ellos es ASP.NET. Cuando una solicitud lleva demasiado tiempo, abortará el hilo por ti. Así que con esto en mente es tonto decir "nunca abortar hilos".
Le aconsejo que averigüe dónde se cuelga este código (el seguimiento de la pila de la excepción ThreadAbortException debería proporcionarle mucha información). Si siempre se cuelga en el mismo lugar (probablemente es un punto muerto), averigüe con Reflector si el aborto de un hilo en ese punto resultará en una corrupción del estado. Con esa información, quizás ya pueda solucionar el problema (quizás haya bloqueado un objeto de esa biblioteca) o puede enviar un correo al escritor de esa biblioteca. Si todo esto no ayuda y ves que no hay riesgo de abortarlo, sé pragmático y mátalo :-)
Sin embargo, si hay un cambio en la corrupción de cualquier estado, debe intentar ir con la respuesta de Mark Byers. Es decir: intente ejecutar esa biblioteca en su propio dominio de aplicación. De esta manera, puede descargar el dominio de aplicación completo y no hay ningún cambio que afecte a su aplicación.
Mi compañero de trabajo está utilizando una biblioteca de .NET de terceros para la que no tenemos el código fuente. Estamos usando un ThreadPool para tener una gran cantidad de llamadas de subprocesos en esta biblioteca, y ocasionalmente uno de los subprocesos simplemente se colgará para siempre mientras que el resto de ellos avanza alegremente.
Así que queremos usar el temido Thread.Abort
para matar tales hilos. He hecho esto antes al girar mis propios hilos, pero nunca he usado un ThreadPool. Si seguimos los tiempos de inicio de cada tarea de esta manera:
static Dictionary<Thread, DateTime> started = new Dictionary<Thread, DateTime>();
static void DoSomeWork(object foo)
{
lock(started)
started[Thread.CurrentThread] = DateTime.Now;
SomeBuggyLibraryThatMightInfiniteLoopOrSomething.callSomeFunction(doo);
lock(started)
started.Remove(Thread.CurrentThread);
}
Entonces, ¿podemos bloquear e iterar sobre los hilos en ejecución y llamar a Thread.Abort
para matarlos? Y si lo hacemos, ¿entonces deberemos agregar un nuevo hilo al ThreadPool para reemplazar el que acabamos de matar, o el ThreadPool se encargará de eso?
EDIT: Estoy muy consciente de todos los problemas potenciales con Thread.Abort
. Sé que, idealmente, nunca debería usarse en el código de producción, y que no necesariamente detiene el hilo, y que si abortas un hilo mientras el hilo ha adquirido un bloqueo, puedes colgar otros hilos, etc. Pero ahora estamos en una fecha límite muy ajustada y tenemos razones razonables para creer que en este caso en particular, podemos llamar a Thread.Abort
sin poner en peligro todo el proceso, y nos gustaría evitar volver a escribir este programa para eliminar el ThreadPool a menos que sea absolutamente necesario.
Entonces, lo que quiero saber es esto: dado que llamaremos Thread.Abort
en un subproceso que pertenece a ThreadPool, ¿hay algún problema especial causado por estos subprocesos de ThreadPool y tenemos que girar manualmente un nuevo subproceso? para reemplazar el que se mató o ThreadPool lo hará por nosotros?
Lea ''Abortable Thread Pool''
por Stephen Toub. Él proporciona el código fuente para un grupo de hilos abortable. Es una lectura interesante.
Llama a su propia devolución de llamada ''HandleItem'' cuando pone en cola la agrupación de hilos. Dentro de ''HandleItem'', luego ejecuta la devolución de llamada real, después de agregar el hilo actual a una lista de diccionarios dentro de su clase de contenedor.
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem));
HandleItem(...) {
...
_threads.Add(item, Thread.CurrentThread);
...
}
Utiliza un Diccionario para vincular sus artículos de trabajo a subprocesos, cuando un usuario desea cancelar un subproceso, realiza una búsqueda y cancela ese subproceso en particular.
Dictionary<WorkItem, Thread>() _threads = New Dictionary<WorkItem, Thread>();
No, no deberías llamar a Abortar en hilos en el grupo de hilos. Según mis pruebas locales, parece que ThreadPool vuelve a crear subprocesos si los abortas. Aborté los subprocesos de 1000 subprocesos y aún funcionaba. No sé si debería confiar en este comportamiento, pero tal vez pueda salirse con la suya en este caso. En general, aunque usar Thread.Abort no es la forma correcta de hacerlo.
La forma correcta de llamar a una función en la que no confía para comportarse bien es iniciarla en un nuevo proceso y finalizar el proceso si es necesario.
Para aclarar lo que Mark está diciendo, si llama a Thread.Abort no tiene idea de dónde abortará en el componente de terceros debido a la naturaleza especial de la ThreadAbortException
, por ejemplo, podría dejar abierto un FileStream
.
Personalmente crearía los subprocesos yo mismo, a los que se hace referencia en una lista o cola (ya que ThreadPool
es más adecuado para el fuego y el WaitHandles
o WaitHandles
), y dependiendo de si cree que abortar un subproceso que utiliza el componente de terceros no es tan peligroso. , Abort
.
Si cree que abortar puede dejar la biblioteca de terceros en un estado inaceptable, Join los subprocesos que no se han completado uno por uno, después de un período de tiempo establecido usando un System.Threading.Timer
Alternativamente
Para seguir usando ThreadPool, puedes usar este grupo de subprocesos inteligente .
Tiene otra opción (que tomaría si tuviera un día libre frente a mí):
aplicar ingeniería inversa al componente de terceros con un reflector y, de hecho, corregir la llamada de bloqueo para que sea asíncrono.