问题描述
我有一个多线程的应用程序,我需要取消每项任务在一定时间后,即使在取消的时候,他们使用的非托管资源。现在我用下面的代码(例如,一个控制台应用程序)。在实际应用中,可能发生在非托管资源的延迟。
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:
但我不知道它是否是正确的从安全的角度来看一个真实的应用。
我还用的CancellationToken在不同的变种,但它不给我正确的结果,因为在这里我使用CancellAfter()或.Delay()与入库时间和ceratain时间后取消任务,我得到了以下结果:
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);
}
}
在此情况下,所有任务必须取消,因为Thread.sleep代码()>时间分配给执行每个任务。但是我们可以看到,一些时间来执行
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);
}
}
我也使用并行和初始化取消标记方法里面DO(),和使用计时器到cancell时间跨度后的道理,但都给予同样的结果。
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???
推荐答案
您可以通过使用相同的定时得到相同的结果作为你的原来的中止的版本。例如,下面的代码:
You can get the same results as your original "abort" version by using the same timings. For example, this code:
static void Main()
{
var clt = new CancellationTokenSource();
clt.CancelAfter(1000);
for (int i = 0; i < 10; i++)
{
Task.Run(() => Do(clt.Token));
}
Console.ReadLine();
}
private static void Do(CancellationToken cltToken)
{
Console.WriteLine("Start " + Task.CurrentId);
Thread.Sleep(2000);
if (!cltToken.IsCancellationRequested)
{
Console.WriteLine("End " + Task.CurrentId);
}
else
{
Console.WriteLine("Cancelled "+ Task.CurrentId);
}
}
会产生的东西这类似于:
Will produce something simliar to:
Start 111
Start 112
Start 113
Start 114
Start 115
Start 116
Start 117
Start 118
Start 119
Start 120
Cancelled 111
Cancelled 112
Cancelled 118
Cancelled 116
Cancelled 114
Cancelled 113
Cancelled 117
Cancelled 115
Cancelled 119
Cancelled 120
使用除终止线程 CancellationTokenSource
是一个更好的选择。 Thread.Abort的
是一个糟糕的主意,因为它会中止线程没有提供适当的清理机制。使用令牌可以让你的合作的处理干净利索取消
Using a CancellationTokenSource
is a better option than aborting threads. Thread.Abort
is a bad idea since it aborts the thread without providing proper cleanup mechanisms. Using the token allows you to cooperatively handle the cancellation in a clean manner.
至于为什么你的其他选择是不正常 - 时序你用得有点靠得太近。这是特别的一个问题在调试器下运行时,它会阻止计时(即: CancelAfter
以及 Thread.sleep代码$ C从在同一时间发射$ C>)。如果你在外面跑在Visual Studio宿主进程的发布版本,你可能会发现,他们更可靠地工作。
As for why your other options were not functioning properly - The timings you used were a bit too close together. This is especially an issue when running under the debugger, as it will prevent the timings (ie: CancelAfter
as well as Thread.Sleep
) from firing at the same time. If you run a release build outside of the Visual Studio host process, you'll likely find that they work far more reliably.
这篇关于按时间取消任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!