run cancellationtoken cancel c# .net-4.0 sleep cancellation cancellationtokensource

c# - cancellationtoken - Cómo "dormir" hasta que se solicite el tiempo de espera o la cancelación en.NET 4.0



cancel task run c# (4)

¿Cuál es la mejor manera de dormir una cierta cantidad de tiempo, pero ser capaz de ser interrumpido por un IsCancellationRequested de un CancellationToken ?

Estoy buscando una solución que funcione en .NET 4.0.

Me gustaría escribir

void MyFunc (CancellationToken ct) { //... // simulate some long lasting operation that should be cancelable Thread.Sleep(TimeSpan.FromMilliseconds(10000), ct); }


Acabo de escribir en un blog sobre esto aquí:

CancelaciónToken and Thread.Sleep

en breve:

var cancelled = token.WaitHandle.WaitOne(TimeSpan.FromSeconds(5));

En tu contexto:

void MyFunc (CancellationToken ct) { //... // simulate some long lasting operation that should be cancelable var cancelled = ct.WaitHandle.WaitOne(TimeSpan.FromSeconds(10)); }


Alternativamente, creo que esto es bastante claro:

Task.Delay(waitTimeInMs, cancellationToken).Wait(cancellationToken);


La mejor solución que encontré hasta ahora es:

void MyFunc(CancellationToken ct) { //... var timedOut = WaitHandle.WaitAny(new[] { ct.WaitHandle }, TimeSpan.FromMilliseconds(2000)) == WaitHandle.WaitTimeout; var cancelled = ! timedOut; }

ACTUALIZAR:

La mejor solución hasta ahora es la respuesta aceptada .


Para cancelar una operación asincrónica después de un cierto período de tiempo sin dejar de cancelar la operación manualmente, use algo como lo siguiente

CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; cts.CancelAfter(5000);

Esto causará una cancelación después de cinco segundos. Para cancelar la operación, todo lo que tiene que hacer es pasar el token a su método asíncrono y usar el método token.ThrowifCancellationRequested() , donde ha configurado un controlador de eventos en algún lugar para cts.Cancel() .

Entonces un ejemplo completo es:

CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; cts.CancelAfter(5000); // Set up the event handler on some button. if (cancelSource != null) { cancelHandler = delegate { Cancel(cts); }; stopButton.Click -= cancelHandler; stopButton.Click += cancelHandler; } // Now launch the method. SomeMethodAsync(token);

Donde stopButton es el botón en el que hace clic para cancelar la tarea en ejecución

private void Cancel(CancellationTokenSource cts) { cts.Cancel(); }

y el método se define como

SomeMethodAsync(CancellationToken token) { Task t = Task.Factory.StartNew(() => { msTimeout = 5000; Pump(token); }, token, TaskCreationOptions.None, TaskScheduler.Default); }

Ahora, para permitirle trabajar con el hilo pero también habilitar la cancelación del usuario, tendrá que escribir un método de "bombeo"

int msTimeout; bool timeLimitReached = false; private void Pump(CancellationToken token) { DateTime now = DateTime.Now; System.Timer t = new System.Timer(100); t.Elapsed -= t_Elapsed; t.Elapsed += t_Elapsed; t.Start(); while(!timeLimitReached) { Thread.Sleep(250); token.ThrowIfCancellationRequested(); } } void t_Elapsed(object sender, ElapsedEventArgs e) { TimeSpan elapsed = DateTime.Now - this.readyUpInitialised; if (elapsed > msTimeout) { timeLimitReached = true; t.Stop(); t.Dispose(); } }

Tenga en cuenta que SomeAsyncMethod volverá directamente a la persona que llama. Para bloquear a la persona que llama también tendrá que mover la Task hacia arriba en la jerarquía de llamadas.