У меня есть многопоточное приложение, где мне нужно отменить каждую задачу через определенное время, даже если в момент отмены они используют неуправляемые ресурсы. Сейчас я использую следующий код (например, консольное приложение). В реальном приложении задержка может возникать в неуправляемом ресурсе.
static void Main()
{
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(Do, TaskCreationOptions.LongRunning);
}
Console.ReadLine();
}
private static void Do()
{
new Timer(Thread.CurrentThread.Abort, null, 1000, -1);
try
{
Console.WriteLine("Start " + Task.CurrentId);
Thread.Sleep(2000);
Console.WriteLine("End " + Task.CurrentId);
}
catch (Exception)
{
Console.WriteLine("Thread Aborted " + Task.CurrentId);
}
}
Получите результат:
Но я не уверен, подходит ли это для реального приложения с точки зрения безопасности. Я также использовал CancellationToken в разных вариантах, но это не дает мне правильного результата, потому что, когда я использую CancellAfter() или .Delay() с временным интервалом и отменяю задачу через определенное время, я получаю следующие результаты:
static void Main()
{
for (int i = 0; i < 10; i++)
{
var clt = new CancellationTokenSource();
Task task = new Task(() =>
{
Task.Delay(2000).ContinueWith(_ =>
{
clt.Cancel();
}, clt.Token);
Do(clt.Token);
}, clt.Token);
task.Start();
}
Console.ReadLine();
}
private static void Do(CancellationToken cltToken)
{
Console.WriteLine("Start " + Task.CurrentId);
Thread.Sleep(2500);
if (!cltToken.IsCancellationRequested)
{
Console.WriteLine("End " + Task.CurrentId);
}
else
{
Console.WriteLine("Cancelled "+ Task.CurrentId);
}
}
В этой ситуации все задачи должны быть отменены, потому что Thread.Sleep() > времени, отведенного на выполнение каждой задачи. Но мы можем видеть, что часть времени на выполнение.
Я также использую следующую конструкцию и даю тот же результат:
static void Main()
{
for (int i = 0; i < 10; i++)
{
var clt = new CancellationTokenSource();
clt.CancelAfter(2000);
Task.Factory.StartNew(Do, clt.Token);
}
Console.ReadLine();
}
private static void Do(object obj)
{
var cltToken = (CancellationToken) obj;
Console.WriteLine("Start " + Task.CurrentId);
Thread.Sleep(2500);
if (!cltToken.IsCancellationRequested)
{
Console.WriteLine("End " + Task.CurrentId);
}
else
{
Console.WriteLine("Cancelled "+ Task.CurrentId);
}
}
Я также использую Parallel и инициализирую токен отмены внутри метода Do() и использую Timer для отмены токена после промежутка времени, но все они дают одинаковый результат.
Итак, почему это происходит и как правильно отменить задачу через определенное время???