I have a multi-threaded application where I need to cancel each task after a certain time, even if at the time of cancellation, they use unmanaged resources. Now I use the following code (for example, a console application). In a real application, the delay may occur in the unmanaged resource.
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);
}
}
Get the result:
But I'm not sure whether it is right for a real application from the point of view of safety. I also used CancellationToken in different variants, but it not give me correct result because where i use CancellAfter() or .Delay() with timespan and cancel task after ceratain time I got the following results:
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);
}
}
In this situation all task must be cancelled, because Thread.Sleep() > of time allotted to execute each task. But we can see that some of the time to execute.
I also use following construction and give the same result:
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);
}
}
I also use Parallel and initialize Cancellation Token Inside method Do(), and use Timer to cancell token after timespan, but all give same result.
SO, Why is this happening and what is the correct way to cancel the task after a certain time???