1

I have this asynchronous method :

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

I want to be able to monitor the task that results from calling this function :

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

I have in place a CancellationTokenSource.

How can I make T (or the function Initialize) utilize that sources token such that if it is cancelled, T.IsCancelled will be true?

EDIT

I do not know for certain but I think the answer to my question lies within using a TaskCompletionSource object. The answer given by Mike has lead me to this conclusion...

Will
  • 3,413
  • 7
  • 50
  • 107

4 Answers4

3

From the documentation

A Task will complete in the TaskStatus.Canceled state under any of the following conditions:

  • Its CancellationToken was marked for cancellation before the task started executing,

  • The task acknowledged the cancellation request on its already signaled CancellationToken by throwing an OperationCanceledException that bears the same CancellationToken.

  • The task acknowledged the cancellation request on its already signaled CancellationToken by calling the ThrowIfCancellationRequested method on the CancellationToken.

stuartd
  • 70,509
  • 14
  • 132
  • 163
  • A `CancellationToken` isn't required for a task to be marked as canceled but this is one documented way to achieve that. – Lukazoid Dec 07 '15 at 14:47
  • @Lukazoid actually, if you throw a `OperationCanceledException` and that exception was not linked to the task it will not show the task as canceled. Async tasks are a special case I believe, but if you where doing the same operation in a `Task.Run(SomeFunction, myToken)` the token is required to be linked to the exception to get in to the canceled state. – Scott Chamberlain Dec 07 '15 at 14:49
  • @ScottChamberlain But my point still stands, a `CancellationToken` isn't required, there are other alternatives. – Lukazoid Dec 07 '15 at 14:52
  • @Lukazoid I was just trying to clarify, it is not required *for the OP's case* but it could be required for other cases. – Scott Chamberlain Dec 07 '15 at 14:53
  • This answer makes sense to me; however I am not calling `task.run(() => {/*Do Stuff*/}, /*CancellationToken*/);`. This `async` method is too complex for that (and relies on libraries that are already in place which make use of `async` methods (before I began to explore task cancellation). I just need to know if it is possible for me to see that the `Task T` resultant from calling the `Initialize` function would have it's `IsCancelled` property show `true` if a furnished `CancellationToken` were to have it's `Cancel( )` method called. – Will Dec 07 '15 at 14:58
1

Updated:

Use this method:

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;
}

Consuming task:

var cts = new CancellationTokenSource();

await UntilCompletionOrCancellation(Class.Initialize, cts.Token);

if (!Class.Initialize.IsCompleted)
{
    /*Do Stuff Here*/ 
}

Another approach is to remove async from Initialize

 private static Task Initialize()
 {
    var tcs = new TaskCompletionSource();

    //use TrySetResult or TrySetCancelled 

    return tcs.Task;
 }

You can await this task and check whether is canceled or completed.

Mike
  • 3,766
  • 3
  • 18
  • 32
  • That won't work - I'm already doing something like that, but I need to monitor the `Task` that comes from calling `Class.Initialize` to watch it. This answer does not address my question. – Will Dec 07 '15 at 14:53
  • I will try this in a simple program and see what happens. – Will Dec 07 '15 at 15:06
  • That doesn't work either - An `async Task` function cannot return a value; trying to `return asyncOp` fails. – Will Dec 07 '15 at 15:10
  • @Will sorry forgot return type – Mike Dec 07 '15 at 15:15
  • This still isn't exactly right but I think it does lead me to the correct answer - I believe that I need to just use a `TaskCompletionSource` object and set it's property through `TrySetCancelled` appropriately... – Will Dec 07 '15 at 15:17
  • @Will added some idea using TaskCompletionSource – Mike Dec 07 '15 at 15:29
0

It is enough to just throw an OperationCanceledException from your asynchronous method.

The following writes true to the console:

public static void Main()
{
    Console.WriteLine(DoSomethingAsync().IsCanceled);
}

private static async Task DoSomethingAsync()
{    
    throw new OperationCanceledException();
}

A nicer way to support cancellation is to have your asynchronous method take a CancellationToken as a parameter, it may then use this token to check for cancellation, e.g:

public static async Task DoSomethingAsync(CancellationToken cancellationToken)
{    
    cancellationToken.ThrowIfCancellationRequested();
}
Lukazoid
  • 19,016
  • 3
  • 62
  • 85
0

You need to call CancellationToken.ThrowIfCancellationRequested() inside the method and let the exception bubble up.

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*/ 
}
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431