【问题标题】: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 允许取消单个作业,那么您可以在每个作业上下文中公开一个标志作为属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-01
        • 2017-04-07
        • 1970-01-01
        • 1970-01-01
        • 2014-09-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多