locked
Multi-Threading Cross-Class Cancellation with TPL

    Question

  • All, I have a long running process that I run on a background thread (with cancellation support) using the Task Paralell Library (TPL). The code for this long running taks is contained within `Class Validation`, and when the method

        public bool AsyncRunValidationProcess(TaskScheduler _uiScheduler, 
            CancellationToken _token, dynamic _dynamic = null)
         {
             try
             {
     
                // Note: _uiScheduler is used to update the UI thread with progress infor etc.
     
                for (int i = 0; i < someLargeLoopNumber; i++)
                 {
                     // Cancellation requested from UI Thread.
                     if (_token.IsCancellationRequested) 
                        _token.ThrowIfCancellationRequested();
                 }
                 return true;
             }
             catch (Exception eX)
             {
                 // Do stuff. Display `eX` if cancellation requested.
                 return false;
             }
         }

    is run from `Class Validation` I can cancel the process fine. The cancellation request is handled by the appropriate `delegate` (shown below). However, when I run this method from another class via another method `asyncControlMethod()`, the cancellation stops working. The controller is invoked via

        asyncTask = Task.Factory.StartNew<bool>(() => asyncControlMethod(), token);

    which in turn invokes the method

    valForm.AsyncRunValidationProcess(uiScheduler, token, 
            new List<string>() { strCurrentSiteRelPath }));

    where `valForm` is my accessor to `Class Validation`, the method runs fine, but when I attempt a cancellation the `delegate`

        cancelHandler = delegate 
        {
             UtilsTPL.CancelRunningProcess(asyncTask, cancelSource);
         };

    where

        public static void CancelRunningProcess(Task _task, 
            CancellationTokenSource _cancelSource)
         {
             try
             {
                 _cancelSource.Cancel();
                 _task.Wait(); // On cross-class call it freezes here.
             }
             catch (AggregateException aggEx)
             {
                 if (aggEx.InnerException is OperationCanceledException)
                     Utils.InfoMsg("Operation cancelled at users request.");
                 if (aggEx.InnerException is SqlException)
                     Utils.ErrMsg(aggEx.Message);
             }
         }

    freezes/hangs (with no unhandled exception etc.) on `_task.Wait()`. This I think is to do with the fact that I am cancelling `asyncControlMethod()` which has called `valForm.AsyncRunValidationProcess(...)`, so it is cancelling `asyncControlMethod()` which is causing the current process to hang.

    **I know I am probably being stupid here, but can anyone tell me what I am doing wrong or should be doing to allow such a cancellation proceedure?**

    _Note: I have tried to spawn a child task to run `valForm.AsyncRunValidationProcess(...)`, with its own `CancellationToken` but this has not worked._

    Thanks for your time.


    "Everything should be made as simple as possible, but not simpler" - Einstein



    Monday, May 14, 2012 2:13 PM

Answers

All replies

  • As I read the code I was asking myself why would one need to run one Asynchronous task within the other?  But then I was wondering if the problem is with the cancelation token itself?  Stehpen Toub discusses the association of the token when passing in with the task start, in this post.  http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/c2f614f6-c96c-4821-84cc-050b21aaee45

    JP Cowboy Coders Unite!

    Monday, May 14, 2012 2:34 PM
  • I am looping through an Array of mathods using a generic method `TaskSpin` to reel off methods like `private bool ThisTask1() { ... }`, `private bool ThisTask2() { ... }`, etc. It just so happens that this task is discribed in another class, so to keep the consistancy of my loop and the ascociated `TaskSpin` method, I invoke the required method (the one in the other class, via a method `ThisTaskX() { ...} `. It may be that I will have to treat this method as exceptional an write a seperate piece of code to invoke it. But there must be a way to do what I want using child tasks or some other such magic?


    "Everything should be made as simple as possible, but not simpler" - Einstein

    Monday, May 14, 2012 2:47 PM
  • Please use this Parallel forum: http://social.msdn.microsoft.com/Forums/en-US/parallelextensions

    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us

    Tuesday, May 15, 2012 7:15 AM
    Moderator
  • Mike, just move this thread thanks!


    JP Cowboy Coders Unite!

    Tuesday, May 15, 2012 1:26 PM
  • You're welcome!

    Have a good day Javaman!


    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, May 16, 2012 1:24 AM
    Moderator
  • I think there's no problem with the cancellation. The problem is that you call Task.Wait() on UI thread in CancelRunningProcess. That's the source of freezing your form.

    Stephen Toub has explained it in this blog post:

    http://blogs.msdn.com/b/pfxteam/archive/2011/01/13/10115163.aspx

    Thursday, May 24, 2012 6:39 AM
  • This was the answer http://stackoverflow.com/a/10651160/626442. I was aware abotu the Wait() I was using it for testing. Sorry for the inconvienence. Thanks you very mucg for your time.


    "Everything should be made as simple as possible, but not simpler" - Einstein

    Thursday, May 24, 2012 4:54 PM