我有一个多线程应用程序,我需要在一定时间后取消每个任务,即使在取消时,它们使用非托管资源。现在我使用以下代码(例如,控制台应用程序)。在实际应用中,延迟可能发生在非托管资源中。
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,但它并没有给我正确的结果,因为我在使用带有时间跨度的 CancellationToken 或 .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() 内部初始化 Cancellation Token,并使用 Timer 在时间跨度后取消令牌,但都给出相同的结果。
那么,为什么会发生这种情况以及在一定时间后取消任务的正确方法是什么???