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.