Task cancellation from inside the task body - c#

I read about the Cancellation methods but based on my understanding they all provide control over tasks from outside the task, but if i want to cancel a task from the inside.
For example in this pseudo code:
Task tasks = new Task(() =>
{
bool exists = CheckFromDB();
if (!exists)
break;
}
Can i cancel a task from the inside?
The only idea i got is to trigger an exception inside the task and handle it from outside but surly that is not the way to do.

If you want to truly Cancel the task (e.g. after it's completed the Status property would be set to Canceled), you can do it this way:
var cts = new CancellationTokenSource();
var token = cts.Token;
Task innerCancel = new Task(
() =>
{
if (!CheckFromDB())
{
cts.Cancel();
}
token.ThrowIfCancellationRequested();
},
token);
When you use return task won't be actually canceled, but rather code after the return statement won't be executed, and the task itself will have its state as RanToCompletion.
On a side note it's advised to use Task.Factory.StartNew for .NET 4 and Task.Run for .NET 4.5 instead of constructor to create tasks.

The lambda expression code inside a task behaves just the same as in any other method. If you want to end the task for some reason you can just simply return:
Task task = Task.Run(() =>
{
if(!CheckFromDB())
{
return;
}
}
You can also throw an exception. That will end the task and mark it as faulted but there's no reason to do so if you can avoid it. If you are really responding to some problem that you can't overcome, then yes, just throw an exception.

Related

C#: How to correctly execute auto-generated methods from web service with a timeout in an async method?

I need to call some methods from a web service, specified in WSDL. VisualStudio created the corresponding methods for me, including async variants. The documentation specifies (different) timeouts for those methods, some of them could take several minutes. So what is the best way to implement this?
I have two approaches, but I'm not sure which one is better, or if I should do something completely different:
Variant 1: use generated async method and task.Wait instead of await:
public async Task<ResultType> MyMethod1Async()
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(60000);
Task<ResultType> task = MyWebService.getSomeObjectAsync();
task.Wait(cts.Token);
return task.Result;
}
Variant 2: execute generated synchronous method in Task.Run:
public async Task<ResultType> MyMethod2Async()
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(60000);
Task<ResultType> task = Task.Run(
() => MyWebService.getSomeObject(),
cts.Token);
return await task;
}
Neither option will do what you want.
Variant 1 will block on task.Result regardless of any timeout. Variant 2 will not be cancelled once the method has started running
If the async task does not support cancellation, the best you can do is to return to the caller when the timeout is reached, and let the task continue in the background, any eventual result will be ignored. For example:
public async Task<ResultType> MyMethodAsync<T>(TimeSpan timeout)
{
var task = SomeAsyncMethod<ResultType>();
var timeoutTask = Task.Delay(timeout);
var completedTask = await Task.WhenAny(task, timeoutTask);
if (completedTask == timeoutTask)
{
// Handle timeout somehow
throw new TimeoutException("...");
}
return task.Result;
}
This is obviously not appropriate for compute bound tasks, and if it is possible to use real support for cancellation it should be used.

Running multiple async tasks and waiting for them all to complete

I need to run multiple async tasks in a console application, and wait for them all to complete before further processing.
There's many articles out there, but I seem to get more confused the more I read. I've read and understand the basic principles of the Task library, but I'm clearly missing a link somewhere.
I understand that it's possible to chain tasks so that they start after another completes (which is pretty much the scenario for all the articles I've read), but I want all my Tasks running at the same time, and I want to know once they're all completed.
What's the simplest implementation for a scenario like this?
Both answers didn't mention the awaitable Task.WhenAll:
var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();
await Task.WhenAll(task1, task2);
The main difference between Task.WaitAll and Task.WhenAll is that the former will block (similar to using Wait on a single task) while the latter will not and can be awaited, yielding control back to the caller until all tasks finish.
More so, exception handling differs:
Task.WaitAll:
At least one of the Task instances was canceled -or- an exception was thrown during the execution of at least one of the Task instances. If a task was canceled, the AggregateException contains an OperationCanceledException in its InnerExceptions collection.
Task.WhenAll:
If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.
If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion state before it's returned to the caller.
You could create many tasks like:
List<Task> TaskList = new List<Task>();
foreach(...)
{
var LastTask = new Task(SomeFunction);
LastTask.Start();
TaskList.Add(LastTask);
}
Task.WaitAll(TaskList.ToArray());
You can use WhenAll which will return an awaitable Task or WaitAll which has no return type and will block further code execution simular to Thread.Sleep until all tasks are completed, canceled or faulted.
WhenAll
WaitAll
Any of the supplied tasks completes in a faulted state
A task with the faulted state will be returned. The exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
An AggregateException will be thrown.
None of the supplied tasks faulted but at least one of them was canceled
The returned task will end in the TaskStatus.Canceled state
An AggregateException will be thrown which contains an OperationCanceledException in its InnerExceptions collection
An empty list was given
An ArgumentException will be thrown
The returned task will immediately transition to a TaskStatus.RanToCompletion State before it's returned to the caller.
Doesn't block the current thread
Blocks the current thread
Example
var tasks = new Task[] {
TaskOperationOne(),
TaskOperationTwo()
};
Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);
If you want to run the tasks in a particular/specific order you can get inspiration from this answer.
The best option I've seen is the following extension method:
public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
return Task.WhenAll(sequence.Select(action));
}
Call it like this:
await sequence.ForEachAsync(item => item.SomethingAsync(blah));
Or with an async lambda:
await sequence.ForEachAsync(async item => {
var more = await GetMoreAsync(item);
await more.FrobbleAsync();
});
Yet another answer...but I usually find myself in a case, when I need to load data simultaneously and put it into variables, like:
var cats = new List<Cat>();
var dog = new Dog();
var loadDataTasks = new Task[]
{
Task.Run(async () => cats = await LoadCatsAsync()),
Task.Run(async () => dog = await LoadDogAsync())
};
try
{
await Task.WhenAll(loadDataTasks);
}
catch (Exception ex)
{
// handle exception
}
Do you want to chain the Tasks, or can they be invoked in a parallel manner?
For chaining
Just do something like
Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
and don't forget to check the previous Task instance in each ContinueWith as it might be faulted.
For the parallel manner
The most simple method I came across: Parallel.Invoke
Otherwise there's Task.WaitAll or you can even use WaitHandles for doing a countdown to zero actions left (wait, there's a new class: CountdownEvent), or ...
This is how I do it with an array Func<>:
var tasks = new Func<Task>[]
{
() => myAsyncWork1(),
() => myAsyncWork2(),
() => myAsyncWork3()
};
await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync
I prepared a piece of code to show you how to use the task for some of these scenarios.
// method to run tasks in a parallel
public async Task RunMultipleTaskParallel(Task[] tasks) {
await Task.WhenAll(tasks);
}
// methode to run task one by one
public async Task RunMultipleTaskOneByOne(Task[] tasks)
{
for (int i = 0; i < tasks.Length - 1; i++)
await tasks[i];
}
// method to run i task in parallel
public async Task RunMultipleTaskParallel(Task[] tasks, int i)
{
var countTask = tasks.Length;
var remainTasks = 0;
do
{
int toTake = (countTask < i) ? countTask : i;
var limitedTasks = tasks.Skip(remainTasks)
.Take(toTake);
remainTasks += toTake;
await RunMultipleTaskParallel(limitedTasks.ToArray());
} while (remainTasks < countTask);
}
There should be a more succinct solution than the accepted answer. It shouldn't take three steps to run multiple tasks simultaneously and get their results.
Create tasks
await Task.WhenAll(tasks)
Get task results (e.g., task1.Result)
Here's a method that cuts this down to two steps:
public async Task<Tuple<T1, T2>> WhenAllGeneric<T1, T2>(Task<T1> task1, Task<T2> task2)
{
await Task.WhenAll(task1, task2);
return Tuple.Create(task1.Result, task2.Result);
}
You can use it like this:
var taskResults = await Task.WhenAll(DoWorkAsync(), DoMoreWorkAsync());
var DoWorkResult = taskResults.Result.Item1;
var DoMoreWorkResult = taskResults.Result.Item2;
This removes the need for the temporary task variables. The problem with using this is that while it works for two tasks, you'd need to update it for three tasks, or any other number of tasks. Also it doesn't work well if one of the tasks doesn't return anything. Really, the .Net library should provide something that can do this
If you're using the async/await pattern, you can run several tasks in parallel like this:
public async Task DoSeveralThings()
{
// Start all the tasks
Task first = DoFirstThingAsync();
Task second = DoSecondThingAsync();
// Then wait for them to complete
var firstResult = await first;
var secondResult = await second;
}

How to cancel a task from a TaskCompletionSource?

I'm trying to create an async ProducerConsumerCollection and for that, I'm using this msdn page (http://msdn.microsoft.com/en-us/library/hh873173.aspx (bottom of the page)).
I'm now trying to add a timeout, here is what I do :
public async Task<T> TakeWithTimeout(int timeout)
{
Task<T> takeTask = this.Take();
if (timeout <= 0 || takeTask == await Task.WhenAny(this.tasks.Take(), Task.Delay(timeout)))
{
return await takeTask;
}
else
{
// Timeout
return default(T);
}
}
}
The problem with this code is that, in case of timeout, it does not cancel the task created by the Take() method.
Since this task has been "created" by the TaskCompletionSource, I cannot give it a cancellationToken?
So, how to proceed to cancel it and properly implement this Take with timeout ?
Thanks :)
Writing a cancel-safe async-friendly producer/consumer collection is non-trivial. What you need to do is change Take to accept a CancellationToken as a parameter, and it should register a handler so that when it is cancelled the TaskCompletionSource is cancelled.
I highly recommend you use BufferBlock<T>, which has cancellation support built-in.
If you can't use TPL Dataflow (e.g., you're working in a PCL or have target platforms unsupported by Dataflow), then you can use the producer/consumer collections in my open-source AsyncEx library (such as AsyncProducerConsumerQueue or AsyncCollection). These are both based on AsyncLock and AsyncConditionVariable, a design I describe briefly on my blog (which does not get into the cancellation details). The key behind supporting cancellation in a producer/consumer collection with this design is to support cancellation in AsyncConditionVariable.WaitAsync; once your condition variable type supports cancellation, then your collection will easily support it, too.
I'm just going to post my solution to the question How to cancel a task from a TaskCompletionSource because that is what I needed myself.
I'm guessing this could be used for your specific need, but it's not tied to a specific timeout functionality, so this is a general solution (or so I hope).
This is an extension method:
public static async Task WaitAsync<T>(this TaskCompletionSource<T> tcs, CancellationToken ctok)
{
CancellationTokenSource cts = null;
CancellationTokenSource linkedCts = null;
try {
cts = new CancellationTokenSource();
linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, ctok);
var exitTok = linkedCts.Token;
Func<Task> listenForCancelTaskFnc = async () => {
await Task.Delay(-1, exitTok).ConfigureAwait(false);
};
var cancelTask = listenForCancelTaskFnc();
await Task.WhenAny(new Task[] { tcs.Task, cancelTask }).ConfigureAwait(false);
cts.Cancel();
} finally {
if(linkedCts != null) linkedCts.Dispose();
}
}
Usage:
async Task TestAsync(CancellationToken ctok) {
var tcs = new TaskCompletionSource<bool>();
if (somethingOrTheOther) {
tcs.TrySetResult(true);
}
await tcs.WaitAsync(ctok);
}
The idea is to have a supervisory async Task waiting essentially forever until it is cancelled, which we can use to 'exit early' in case the TaskCompletionSource is not yet satisfied, but we need to exit anyhow due to a cancel request.
The supervisory Task is guaranteed to be cancelled at the end of WaitAsync regardless how it falls out of the WhenAny. Either the TaskCompletionSource is satisfied with a result, and WhenAny completes, briefly leaving the supervisory sleeper task in tact until the next line where cts.Cancel() is called, or it was cancelled with the exitToken, which is a combined token of the passed in ctok or the internal one cts.Token.
Anyhow, I hope this makes sense -- please let me know if this code has any problems...

Odd Task Parallel Library InvalidOperationException

I have the following code to build an advanced data structure which is pulled from SQL Server, then when the retrevial of that data is complete I update the UI. The code used is
private void BuildSelectedTreeViewSectionAsync(TreeNode selectedNode)
{
// Initialise.
SqlServer instance = null;
SqlServer.Database database = null;
// Build and expand the TreeNode.
Task task = null;
task = Task.Factory.StartNew(() => {
string[] tmpStrArr = selectedNode.Text.Split(' ');
string strDatabaseName = tmpStrArr[0];
instance = SqlServer.Instance(this.conn);
database = instance.GetDatabaseFromName(strDatabaseName);
}).ContinueWith(cont => {
instance.BuildTreeViewForSelectedDatabase(this.customTreeViewSql,
selectedNode, database);
selectedNode.Expand();
task.Dispose();
}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
this.MainUiScheduler);
}
This works as it should on my main development machine; that is, it completes the build of the database object, then in the continuation update the UI and disposes the task (Task object).
However, I have been doing some testing on another machine and I get an InvalidOperationException, this is due to the task.Dispose() on task which still in the Running state, but the continuation cont should never fire unless the task has ran to completion.
Here's what the code looks like in the debugger when the exception is thrown:
I am aware that it almost always unneccessary to call Dispose on tasks. This question is more about why the continuation is firing at all here?**
The reason for this is simple, you are calling Dispose on the continuation itself and not on the first task
Your code consists of:
Task task = null;
var task = <task 1>.ContinueWith(t => {
/* task 2 */
task.Dispose();
});
In the above code, task is equal to the continuation (ContinueWith doesn't pass back the original Task, it passes the continuation) and that's what's getting captured in the closure you're passing to ContinueWith.
You can test this by comparing the references of the Task parameter passed into the ContinueWith method with task:
Task task = null;
var task = <task 1>.ContinueWith(t => {
/* task 2 */
if (object.ReferenceEquals(t, task))
throw new InvalidOperationException("Trying to dispose of myself!");
task.Dispose();
});
In order to dispose of the first, you need to break it up into two Task variables and capture the first Task, like so:
var task1 = <task 1>;
var task2 = task1.ContinueWith(t => {
// Dispose of task1 when done.
using (task1)
{
// Do task 2.
}
});
However, because the previous Task is passed to you as a parameter in the ContinueWith method, you don't need to capture task in the closure at all, you can simply call Dispose on the Task passed as a parameter to you:
var task = <task 1>.ContinueWith(t => {
// t = task 1
// task = task 2
// Dispose of task 1 when done.
using (t)
{
// Do task 2.
}
});
I'm pretty sure you are trying to do above is equivelent to:
task = Task.Factory.StartNew(() => ...);
task.ContinueWith(cont => { ... task.Dispose(); });
However, what gets assigned to task variable with your code will be the ContinueWith work item, not the origninal StartNew work item.
More importantly, you probably don't even need to worry about task.Dispose() in this scenario.
The only time there is any real value in doing task.Dispose() is when there is a task.Wait() involved somewhere, which allocates an OS wait handle resource under the covers.
More info:
http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/7b3a42e5-4ebf-405a-8ee6-bcd2f0214f85

How to implement cancellation of shared Task:s in C#

All, here is a question about design/best practices of a complex case of canceling Task:s in C#. How do you implement cancellation of a shared task?
As a minimal example, lets assume the following; we have a long running, cooperatively cancellable operation 'Work'. It accepts a cancellation token as argument and throws if it has been canceled. It operates on some application state and returns a value. Its result is independently required by two UI components.
While the application state is unchanged, the value of the Work function should be cached, and if one computation is ongoing, a new request should not start a second computation but rather start waiting for a result.
Either of the UI components should be able to cancel it's Task without affecting the other UI components task.
Are you with me so far?
The above can be accomplished by introducing an Task cache that wraps the real Work task in TaskCompletionSources, whose Task:s are then returned to the UI components. If a UI component cancels it's Task, it only abandons the TaskCompletionSource Task and not the underlying task. This is all good. The UI components creates the CancellationSource and the request to cancel is a normal top down design, with the cooperating TaskCompletionSource Task at the bottom.
Now, to the real problem. What to do when the application state changes? Lets assume that having the 'Work' function operate on a copy of the state is not feasible.
One solution would be to listen to the state change in the task cache (or there about). If the cache has a CancellationToken used by the underlying task, the one running the Work function, it could cancel it. This could then trigger a cancellation of all attached TaskCompletionSources Task:s, and thus both UI components would get Canceled tasks. This is some kind of bottom up cancellation.
Is there a preferred way to do this? Is there a design pattern that describes it some where?
The bottom up cancellation can be implemented, but it feel a bit weird. The UI-task is created with a CancellationToken, but it is canceled due to another (inner) CancellationToken. Also, since the tokens are not the same, the OperationCancelledException can't just be ignored in the UI - that would (eventually) lead to an exception being thrown in the outer Task:s finalizer.
Here's my attempt:
// the Task for the current application state
Task<Result> _task;
// a CancellationTokenSource for the current application state
CancellationTokenSource _cts;
// called when the application state changes
void OnStateChange()
{
// cancel the Task for the old application state
if (_cts != null)
{
_cts.Cancel();
}
// new CancellationTokenSource for the new application state
_cts = new CancellationTokenSource();
// start the Task for the new application state
_task = Task.Factory.StartNew<Result>(() => { ... }, _cts.Token);
}
// called by UI component
Task<Result> ComputeResultAsync(CancellationToken cancellationToken)
{
var task = _task;
if (cancellationToken.CanBeCanceled && !task.IsCompleted)
{
task = WrapTaskForCancellation(cancellationToken, task);
}
return task;
}
with
static Task<T> WrapTaskForCancellation<T>(
CancellationToken cancellationToken, Task<T> task)
{
var tcs = new TaskCompletionSource<T>();
if (cancellationToken.IsCancellationRequested)
{
tcs.TrySetCanceled();
}
else
{
cancellationToken.Register(() =>
{
tcs.TrySetCanceled();
});
task.ContinueWith(antecedent =>
{
if (antecedent.IsFaulted)
{
tcs.TrySetException(antecedent.Exception.GetBaseException());
}
else if (antecedent.IsCanceled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(antecedent.Result);
}
}, TaskContinuationOptions.ExecuteSynchronously);
}
return tcs.Task;
}
It sounds like you want a greedy set of task operations - you have a task result provider, and then construct a task set to return the first completed operation, ex:
// Task Provider - basically, construct your first call as appropriate, and then
// invoke this on state change
public void OnStateChanged()
{
if(_cts != null)
_cts.Cancel();
_cts = new CancellationTokenSource();
_task = Task.Factory.StartNew(() =>
{
// Do Computation, checking for cts.IsCancellationRequested, etc
return result;
});
}
// Consumer 1
var cts = new CancellationTokenSource();
var task = Task.Factory.StartNew(() =>
{
var waitForResultTask = Task.Factory.StartNew(() =>
{
// Internally, this is invoking the task and waiting for it's value
return MyApplicationState.GetComputedValue();
});
// Note this task cares about being cancelled, not the one above
var cancelWaitTask = Task.Factory.StartNew(() =>
{
while(!cts.IsCancellationRequested)
Thread.Sleep(25);
return someDummyValue;
});
Task.WaitAny(waitForResultTask, cancelWaitTask);
if(cancelWaitTask.IsComplete)
return "Blah"; // I cancelled waiting on the original task, even though it is still waiting for it's response
else
return waitForResultTask.Result;
});
Now, I haven't fully tested this, but it should allow you to "cancel" waiting on a task by cancelling the token (and thus forcing the "wait" task to complete first and hit the WaitAny), and allow you to "cancel" the computation task.
The other thing is to figure out a clean way of making the "cancel" task wait without horrible blocking. It's a good start I think.

Categories