【问题标题】:Task T.IsCancelled = false; How can I make this true?任务 T.IsCancelled = false;我怎样才能做到这一点?
【发布时间】:2016-03-12 04:59:48
【问题描述】:

我有这个异步方法:

private static async Task Initializ( ) { /*Do Stuff Here*/ }

我希望能够监控调用此函数产生的任务:

Task T = Class.Initialize( );
if (T.IsCancelled){ /*Do Stuff Here*/ }

我有一个CancellationTokenSource

我怎样才能使T(或函数Initialize)利用该源令牌,这样如果它被取消,T.IsCancelled 将是真实的?

编辑

我不确定,但我认为我的问题的答案在于使用TaskCompletionSource 对象。 Mike给出的答案让我得出了这个结论……

【问题讨论】:

    标签: c# wpf asynchronous desktop-application cancellationtokensource


    【解决方案1】:

    来自the documentation

    任务将在 TaskStatus.Canceled 状态下完成 以下条件:

    • 它的 CancellationToken 在任务之前被标记为取消 开始执行,

    • 任务在其已发出信号时确认取消请求 CancellationToken 通过抛出一个 OperationCanceledException 相同的 CancellationToken。

    • 任务在其已发出信号时确认取消请求 CancellationToken 通过调用 ThrowIfCancellationRequested 方法 在 CancellationToken 上。

    【讨论】:

    • CancellationToken 不需要将任务标记为已取消,但这是实现此目的的一种记录方式。
    • @Lukazoid 实际上,如果您抛出 OperationCanceledException 并且该异常未链接到任务,它不会将任务显示为已取消。我相信异步任务是一种特殊情况,但是如果您在 Task.Run(SomeFunction, myToken) 中执行相同的操作,则需要将令牌链接到异常才能进入取消状态。
    • @ScottChamberlain 但我的观点仍然成立,CancellationToken 不是必需的,还有其他选择。
    • @Lukazoid 我只是想澄清一下,对于 OP 的情况不需要它,但对于其他情况可能需要它。
    • 这个答案对我来说很有意义;但是我没有打电话给task.run(() => {/*Do Stuff*/}, /*CancellationToken*/);。这个async 方法太复杂了(并且依赖于已经使用async 方法的库(在我开始探索任务取消之前)。我只需要知道我是否有可能看到调用Initialize 函数产生的Task T 将有它的IsCancelled 属性显示true 如果一个有家具的CancellationToken 要调用它的Cancel( ) 方法。
    【解决方案2】:

    更新:

    使用这个方法:

    async Task<Task> UntilCompletionOrCancellation(Task asyncOp, CancellationToken ct)
    {
       var tcs = new TaskCompletionSource<bool>(); 
    
       using(ct.Register(() => tcs.TrySetResult(true)))
           await Task.WhenAny(asyncOp, tcs.Task); 
    
       return asyncOp;
    }
    

    消费任务:

    var cts = new CancellationTokenSource();
    
    await UntilCompletionOrCancellation(Class.Initialize, cts.Token);
    
    if (!Class.Initialize.IsCompleted)
    {
        /*Do Stuff Here*/ 
    }
    

    另一种方法是从 Initialize 中删除异步

     private static Task Initialize()
     {
        var tcs = new TaskCompletionSource();
    
        //use TrySetResult or TrySetCancelled 
    
        return tcs.Task;
     }
    

    你可以等待这个任务,看看是取消还是完成。

    【讨论】:

    • 那行不通——我已经在做类似的事情了,但我需要监视来自调用Class.InitializeTask 来观看它。这个答案没有解决我的问题。
    • 我将在一个简单的程序中尝试一下,看看会发生什么。
    • 这也不起作用 - async Task 函数不能返回值;尝试return asyncOp 失败。
    • @Will 抱歉忘记返回类型
    • 这仍然不完全正确,但我认为它确实引导我找到正确的答案 - 我相信我只需要使用 TaskCompletionSource 对象并通过 TrySetCancelled 适当地设置它的属性。 ..
    【解决方案3】:

    只需从您的异步方法中抛出一个OperationCanceledException 就足够了。

    下面将true写入控制台:

    public static void Main()
    {
        Console.WriteLine(DoSomethingAsync().IsCanceled);
    }
    
    private static async Task DoSomethingAsync()
    {    
        throw new OperationCanceledException();
    }
    

    支持取消的更好方法是让您的异步方法将CancellationToken 作为参数,然后它可以使用此标记来检查取消,例如:

    public static async Task DoSomethingAsync(CancellationToken cancellationToken)
    {    
        cancellationToken.ThrowIfCancellationRequested();
    }
    

    【讨论】:

      【解决方案4】:

      你需要在方法内部调用CancellationToken.ThrowIfCancellationRequested(),让异常冒泡。

      CancellationTokenSource cts = new CancellationTokenSource();
      Task T = Class.Initialize(cts.Token);
      if (T.IsCancelled){ /*Do Stuff Here*/ }
      
      private static async Task Initializ(CancellationToken token ) 
      {
        /*Do Stuff Here*/ 
        token.ThrowIfCancellationRequested();
        /*Do More Stuff Here*/ 
      }
      

      【讨论】:

        猜你喜欢
        • 2022-11-09
        • 1970-01-01
        • 1970-01-01
        • 2018-10-05
        • 2015-05-01
        • 1970-01-01
        • 2012-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多