【问题标题】:How to know if a task was cancelled or the wait period is over如何知道任务是否被取消或等待期结束
【发布时间】:2016-04-10 02:58:35
【问题描述】:
在特定的业务场景中,有多个任务并行运行。只要最终用户愿意,我就使用CancellationToken 取消这些任务。
我还需要在所有任务运行一段时间后重新启动它们,比如说 3 小时。为此,我使用:
_cts.CancelAfter(TimeSpan.FromHours(3))
这很好用。但是,当 3 小时结束时,任务会自动取消并出来。因此,我无法分别检测这两种情况,即:取消是由于用户想要取消还是因为 3 小时已到。
我知道我们可以使用包含上次运行时间的Datetime 变量并将其推送到我们的任务中。然后我们可以根据当前的时间差和它上次运行的时间来终止任务。但我更关注 TPL 如何帮助解决这个问题。
【问题讨论】:
标签:
.net
parallel-processing
task-parallel-library
task
【解决方案1】:
我认为仅使用 TPL 是没有办法的。我使用 System.Timers.Timer 做了一个解决方法,这是我的示例:
public static void DifferencingCancelAfterAndCancel()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Task task = new Task(() =>
{
for (int i = 0; i < int.MaxValue; i++)
{
token.ThrowIfCancellationRequested();
token.WaitHandle.WaitOne(1000);
Console.WriteLine("To cancel task press 'q': " + i);
}
}, token);
task.Start();
System.Timers.Timer timer = new System.Timers.Timer(10000);
timer.Elapsed += (sender, args) =>
{
if (!task.IsCanceled)
{
tokenSource.Cancel();
Console.WriteLine("Task was cancelled by timer!");
}
else Console.WriteLine("Task has already been cancelled by user");
};
timer.Enabled = true;
var k = Console.ReadLine();
if (k == "q")
{
if (!task.IsCanceled)
{
tokenSource.Cancel();
Console.WriteLine("Task was cancelled by user!");
}
else Console.WriteLine("Task has already been cancelled by timer");
}
Console.WriteLine("Press any key to finish");
Console.ReadLine();
}
您声明了一个将在 10 秒内结束的计时器。在那之后,Elapsed event 将触发 lambda 函数,您可以将逻辑放在那里。取消任务的另一种方法是当用户点击'q'时,您可以在其中放置一些其他逻辑。
希望对你有帮助
【解决方案2】:
当您响应用户输入而取消时,您肯定可以在 UI 事件处理程序中设置一个标志吗?
这不会由超时设置,因此您可以区分它们。
如果 UI 允许取消单个作业,那么您可以在每个作业上下文中公开一个标志作为属性。