tpl programming parallel new net for examples example .net deadlock parallel-processing task task-parallel-library

programming - Eliminando una tarea estancada en.NET 4 TPL



tpl c# (3)

Simplemente llame a Task.Wait(timespanToWait) .

Si la tarea no se completa después del intervalo de tiempo especificado, se cancela.

Me gustaría comenzar a utilizar la Biblioteca de tareas paralelas , ya que este es el marco recomendado en el futuro para realizar operaciones asincrónicas. Una cosa que no he podido encontrar es cualquier medio de Aborto forzoso, como lo que proporciona Thread.Abort.

Mi preocupación particular es que programe tareas que ejecutan código en el que no deseo confiar por completo. En particular, no puedo estar seguro de que este código que no es de confianza no se estancará y, por lo tanto, no puedo estar seguro de si alguna vez se completará una planificación de Tarea I utilizando este código. Quiero mantenerme alejado del verdadero aislamiento de AppDomain (debido a la sobrecarga y la complejidad de las referencias), pero tampoco quiero dejar un thread de tarea rondando, estancado. ¿Hay alguna manera de hacer esto en TPL?


Dan No creo que Task.Wait (timeout) cancelará esta tarea, hay Overload Task.Wait (timeout, cancelationToken), pero eso solo arroja OperationCanceledException en la tarea. Espera cuando token es señalizado.

Tarea. Espere solo bloques hasta que finalice cualquiera de las tareas o expire el tiempo de espera, no cancela ni cancela la tarea. Una tarea tan estancada seguirá colgando en ThreadPool. No puede deshacerse de la tarea no completada (InvalidOperation).

Estoy escribiendo el mismo tipo de aplicación que tú y yo escribimos mi propio TaskScheduler que permite Abortar (y no está usando threadpool :().

Pero tengo mucha curiosidad sobre cómo resolvió este problema. Por favor respóndeme


La forma de hacerlo es con un CancellationToken y el nuevo modelo de cancelación. El nuevo modelo de cancelación está integrado en .NET Framework en varios tipos. Los más importantes son System.Threading.Task, System.Threading.Tasks.Task, System.Threading.Tasks.Task y System.Linq.ParallelEnumerable.

Aquí hay un ejemplo de tu problema. Este código siempre se estancará porque el código de llamada toma primero un bloqueo y luego la tarea interbloqueada intenta obtener el mismo bloqueo.

public void Example() { object sync = new Object(); lock (sync) { CancellationTokenSource canceller = new CancellationTokenSource(); ManualResetEvent started = new ManualResetEvent(false); Task deadlocked = Task.Factory.StartNew(() => { started.Set(); // EVIL CODE: This will ALWAYS deadlock lock(sync) { }; }, canceller.Token); // Make sure task has started. started.WaitOne(); canceller.Cancel(); try { // Wait for task to cancel. deadlocked.Wait(); } catch (AggregateException ex) { // Ignore canceled exception. SIMPLIFIED! if (!(ex.InnerException is TaskCanceledException)) throw; } } }

La cancelación de tareas en el TPL es cooperativa. En otras palabras, esto siempre se estancará porque nada maneja el token de cancelación que se configura como cancelado porque el hilo de la tarea está bloqueado.

Hay una forma de evitar esto, pero todavía depende de los autores del código no confiable para hacer lo correcto:

public static void Example2() { Mutex sync = new Mutex(true); CancellationTokenSource canceller = new CancellationTokenSource(); bool started = false; Task deadlocked = Task.Factory.StartNew(() => { started = true; // EVIL CODE: This will ALWAYS deadlock WaitHandle.WaitAny(new WaitHandle[] { canceller.Token.WaitHandle, sync }); }, canceller.Token); // Make sure task has started. while (!started) { } canceller.Cancel(); try { // Wait for task to cancel. deadlocked.Wait(); } catch (AggregateException ex) { // Ignore canceled exception. SIMPLIFIED! if (!(ex.InnerException is TaskCanceledException)) throw; } }

Puntos a tener en cuenta; la cancelación es cooperativa. Puede usar Token.WaitHandle para obtener un identificador y esperarlo junto con los identificadores de otras primitivas de sincronización. Mutex es mucho más lento que Monitor (o bloqueo).

Realmente, si no confías en el autor del código lo suficiente como para que implementen la cancelación cooperativa, entonces cuestionaré la sensatez de que se ejecuten dentro de tu AppDomain en el mismo hilo.

Para más detalles, ver:

http://msdn.microsoft.com/en-us/library/dd997364.aspx

http://msdn.microsoft.com/en-us/library/dd537607.aspx

http://msdn.microsoft.com/en-us/library/ee191552.aspx