Locked How do you cancel a Task?

  • 2012년 2월 14일 화요일 오후 1:02
     
      코드 있음

    Hi, I am new to the Async CTP.  I have been using the Reactive RX framework for about a year, so I am very familiar with how to do things using that framework.

    My question is, how do you cancel a Task with the Async CTP?

    For example:

    Assume you're creating a WP7 or Silverlight app.

    You navigate to a page, and after 10 seconds, you do some work like this:

    void OnNavigatedTo()
    {
        await TaskEx.Delay(TimeSpan.FromSeconds(10));
    
        DoSomething();
    }

    So you navigate to page, and after 10 seconds, you call the DoSomething function.

    What if you exit the page before 10 seconds?  E.g. after 2 seconds, user hits back button, thus exiting the page.

    How do you make it so that you DON'T execute DoSomething after another 8 seconds pass?

    In Reactive framework, this is very easy to accomplish.  You simply have a page-level CompositeDisposable, and add all your subscriptions to that disposable.

    Then when you exit the page, you just do CompositeDisposable.Dispose(), and you unregister all your subscriptions!

    What is the equivalent mechanism in Async CTP?

    Thank you!



    • 편집됨 Arash Emami 2012년 2월 14일 화요일 오후 2:12
    •  

모든 응답

  • 2012년 2월 14일 화요일 오후 5:35
    중재자
     
     

    Typically, this would be handled via the .NET Framework's Co-operative cancellation mechanism and use a CancellationTokenSource/CancellationToken.

    This lets you control the cancellation and what happens.  Basically, your main section would just setup a CancellationTokenSource, and pass in a token (source.Token) to this routine.  It could then check the properties on the Token, such as IsCancellationRequested, and change behavior as desired (ie: return there).  Note that many of the Async methods that return awaitables also have overloads that take a CancellationToken, which allows the method to cancel early, as well.

    To perform the cancelation (ie: if you exit the page), you just call source.Cancel(). 


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

  • 2012년 2월 29일 수요일 오전 1:39
     
      코드 있음

    Typically, this would be handled via the .NET Framework's Co-operative cancellation mechanism and use a CancellationTokenSource/CancellationToken.

    This lets you control the cancellation and what happens.  Basically, your main section would just setup a CancellationTokenSource, and pass in a token (source.Token) to this routine.  It could then check the properties on the Token, such as IsCancellationRequested, and change behavior as desired (ie: return there).  Note that many of the Async methods that return awaitables also have overloads that take a CancellationToken, which allows the method to cancel early, as well.

    To perform the cancelation (ie: if you exit the page), you just call source.Cancel(). 


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    Hi Reed,

    The problem I have is that the async method in question is a converted IObservable<T> (which I convert from IObservable to Task by calling the extension method "ToTask").

    The "ToTask" method does not take in a CancellationToken though.

    Here is an example of how I am using it:

            protected async override void OnInitialPageLoad()
            {
                vm = (DetailedZuneAppViewModel)ViewModel;
    
                InitializePivotLoadingItemHandler();
    
                this.DataContext = vm;
    
                await GetExtendedZuneAppInfo();
    
                SystemTray.SetIsVisible(this, false);
    
                await OnPageLoadSB.BeginWithNotification().Take(1).ToTask();
    
                progressBar.IsIndeterminate = true;
                IsHitTestVisible = true;
    
    
                await TaskEx.WhenAll(GetAppReviewsAsync(10), GetRecommendedAppsAsync());
    
                progressBar.IsIndeterminate = false;
            }

    It's nice and straightforward and elegant because of the "await" keyword.

    After every line should I be checking the CancellationTokenSource's state to see if it has been cancelled, and if so, not proceed with the rest of the function?

    Because in between every one of those awaits in the function above, the user could have hit the back button and exited out of that page, in which case I don't want to proceed with the remainder of that function.

    I can imagine that getting very ugly very quickly!

  • 2012년 2월 29일 수요일 오전 2:24
    중재자
     
     답변됨


    After every line should I be checking the CancellationTokenSource's state to see if it has been cancelled, and if so, not proceed with the rest of the function?

    Because in between every one of those awaits in the function above, the user could have hit the back button and exited out of that page, in which case I don't want to proceed with the remainder of that function.

    I can imagine that getting very ugly very quickly!

    Unfortunately, if you're using an API that doesn't support cancellation, you pretty much have to handle it yourself this way.  Calling token.ThrowIfCanceledRequested() in between elements is a reasonable way to handle this, and likely the best option.

    Over time, I do hope that more APIs will support CancellationToken directly, in which case you could just pass them a token.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • 답변으로 표시됨 Arash Emami 2012년 2월 29일 수요일 오전 8:09
    •  
  • 2012년 2월 29일 수요일 오전 8:10
     
     

    Gotcha.  I made it even simpler, since it shouldn't throw an exception after the user has exited the page.  I just made a bool variable "hasPageExited" and then check it after every await call.  Works ok.