取消任务的另一种方法

时间:2016-07-17 18:05:35

标签: c# multithreading

我有一个简单的控制台应用程序

<?php echo Html::img('../../uploads/ring.jpg',['class' => 'img-center', 'width'=>150, 'heigth'=>150, 'alt'=>'no image']) ?>

我试图开始新的任务,并在一段时间后取消它。有没有其他方法来实现此结果而不是使用此

class Program
{
    private static void MyTask(object obj)
    {
        var cancellationToken = (CancellationToken) obj;
        if(cancellationToken.IsCancellationRequested)
            cancellationToken.ThrowIfCancellationRequested();

        Console.WriteLine("MyTask() started");
        for (var i = 0; i < 10; i++)
        {
            try
            {
                if (cancellationToken.IsCancellationRequested)
                    cancellationToken.ThrowIfCancellationRequested();

            }
            catch (Exception ex)
            {
                return;
            }


            Console.WriteLine($"Counter in MyTask() = {i}");
            Thread.Sleep(500);
        }
        Console.WriteLine("MyTask() finished");
    }
    static void Main(string[] args)
    {
        var cancelationTokenSource = new CancellationTokenSource();
        var task = Task.Factory.StartNew(MyTask, cancelationTokenSource.Token,
            cancelationTokenSource.Token);

        Thread.Sleep(3000);

        try
        {
            cancelationTokenSource.Cancel();
            task.Wait();
        }
        catch (Exception ex)
        {
            if(task.IsCanceled)
                Console.WriteLine("Task has been cancelled");

            Console.WriteLine(ex.Message);
        }
        finally
        {
            cancelationTokenSource.Dispose();
            task.Dispose();
        }

        Console.WriteLine("Main finished");
        Console.ReadLine();
    }
}
for for循环中的每次迭代?为什么我们必须在每次迭代时检查cancellationToken.IsCancellationRequested,也许我们可以使用其他东西?

2 个答案:

答案 0 :(得分:1)

在这种特定情况下,您可以避免使用.ThrowIfCancellationRequested(),而只需使用break来停止执行循环,然后完成TaskThrowIfCancellationRequested在更深层次的任务树中更有用,其中有更多的后代,并且更难以保持取消。

if (cancellationToken.IsCancellationRequested)
{
    break;
}

斯蒂芬·图布(Stephen Toub)有一个good explanation关于如何投掷OCE更像是一种承认。

  

如果任务的主体也在监视取消令牌并抛出包含该令牌的OperationCanceledException(这是ThrowIfCancellationRequested所做的),那么当任务看到OCE时,它会检查是否OCE的令牌与任务的令牌匹配。如果是,则该异常被视为对合作取消的确认,并且任务转换为已取消状态(而不是故障状态)。

答案 1 :(得分:0)

不确定您对每次迭代检查的异议是什么,但如果您不想检查每次迭代,无论出于何种原因,请检查i的值:

E.g。这会检查每个第10个循环:

if (i % 10 == 0 && cancellationToken.IsCancellationRequested)

您必须检查的原因是,您可以决定最好停止任务的位置,以便工作不会处于不一致状态。虽然通过不频繁检查可以实现的所有目标都是取消速度较慢的任务,但这可能会导致用户体验的响应速度降低。例如。任务将在500毫秒之前结束,现在它可能需要10倍,5秒。

但是,如果每个循环非常快,并且每个循环检查标志证明显着增加了任务所花费的总时间,那么检查每个n循环就会产生。