What is the correct way to cancel the following?
var tcpListener = new TcpListener(connection);
tcpListener.Start();
var client = await tcpListener.AcceptTcpClientAsync();
Simply calling tcpListener.Stop() seems to result in an ObjectDisposedException and the AcceptTcpClientAsync method doesn't accept a CancellationToken structure.
Am I totally missing something obvious?
Assuming that you don't want to call the Stop method on the TcpListener class, there's no perfect solution here.
If you're alright with being notified when the operation doesn't complete within a certain time frame, but allowing the original operation to complete, then you can create an extension method, like so:
public static async Task<T> WithWaitCancellation<T>(
this Task<T> task, CancellationToken cancellationToken)
{
// The tasck completion source.
var tcs = new TaskCompletionSource<bool>();
// Register with the cancellation token.
using(cancellationToken.Register( s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs) )
{
// If the task waited on is the cancellation token...
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
}
// Wait for one or the other to complete.
return await task;
}
The above is from Stephen Toub's blog post "How do I cancel non-cancelable async operations?".
The caveat here bears repeating, this doesn't actually cancel the operation, because there is not an overload of the AcceptTcpClientAsync method that takes a CancellationToken, it's not able to be cancelled.
That means that if the extension method indicates that a cancellation did happen, you are cancelling the wait on the callback of the original Task, not cancelling the operation itself.
To that end, that is why I've renamed the method from WithCancellation to WithWaitCancellation to indicate that you are cancelling the wait, not the actual action.
From there, it's easy to use in your code:
// Create the listener.
var tcpListener = new TcpListener(connection);
// Start.
tcpListener.Start();
// The CancellationToken.
var cancellationToken = ...;
// Have to wait on an OperationCanceledException
// to see if it was cancelled.
try
{
// Wait for the client, with the ability to cancel
// the *wait*.
var client = await tcpListener.AcceptTcpClientAsync().
WithWaitCancellation(cancellationToken);
}
catch (AggregateException ae)
{
// Async exceptions are wrapped in
// an AggregateException, so you have to
// look here as well.
}
catch (OperationCancelledException oce)
{
// The operation was cancelled, branch
// code here.
}
Note that you'll have to wrap the call for your client to capture the OperationCanceledException instance thrown if the wait is cancelled.
I've also thrown in an AggregateException catch as exceptions are wrapped when thrown from asynchronous operations (you should test for yourself in this case).
That leaves the question of which approach is a better approach in the face of having a method like the Stop method (basically, anything which violently tears everything down, regardless of what is going on), which of course, depends on your circumstances.
If you are not sharing the resource that you're waiting on (in this case, the TcpListener), then it would probably be a better use of resources to call the abort method and swallow any exceptions that come from operations you're waiting on (you'll have to flip a bit when you call stop and monitor that bit in the other areas you're waiting on an operation). This adds some complexity to the code but if you're concerned about resource utilization and cleaning up as soon as possible, and this choice is available to you, then this is the way to go.
If resource utilization is not an issue and you're comfortable with a more cooperative mechanism, and you're not sharing the resource, then using the WithWaitCancellation method is fine. The pros here are that it's cleaner code, and easier to maintain.
While casperOne's answer is correct, there's a cleaner potential implementation to the WithCancellation (or WithWaitCancellation) extension method that achieves the same goals:
static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
First we have a fast-path optimization by checking whether the task has already completed.
Then we simply register a continuation to the original task and pass on the CancellationToken parameter.
The continuation extracts the original task's result (or exception if there is one) synchronously if possible (TaskContinuationOptions.ExecuteSynchronously) and using a ThreadPool thread if not (TaskScheduler.Default) while observing the CancellationToken for cancellation.
If the original task completes before the CancellationToken is canceled then the returned task stores the result, otherwise the task is canceled and will throw a TaskCancelledException when awaited.
Related
The Task does not maintain a wait handle for performance reasons, and only lazily constructs one if the code were to ask one of it.
How then does a Task know it has been completed?
One would argue that the implementer sets the result on the TaskCompletionSource in their implementation but that would explain only the modern implementations and re-writes such as System.IO.FileStream.Begin/EndReadTask.
I followed the Task.IsComplete property; almost in every instance, an internal bitwise flag field (m_stateFlags) is set by the TrySetResult / TrySetException methods to indicate the status of the task.
But that does not cover all cases.
What about a method such as this?
public async Task FooAsync()
{
await Task.Run(() => { });
}
How then does a Task know it has been completed?
As I describe on my blog (overview, more detail), there are two kinds of tasks: Delegate Tasks (which execute code) and Promise Tasks (which represent an event).
Delegate Tasks complete themselves when their delegate completes.
Promise Tasks are completed from an external signal, using TaskCompletionSource<T> (or equivalent methods that are internal to the BCL).
I am answering my own question because I have suddenly remembered that I know the answer to it.
When using the C# Language Support Features
It's the state machine.
If the implementer of the asynchronous method used the C# language support such as the async keyword in the method declaration and the await keyword inside the method body to await an operation intrinsic to the task, then to the extent of the task he is implementing, the state machine signals task completion by setting the result of the task.
For e.g. if his implementation was as such:
// client code
public async void TopLevelMethod()
{
await MyMethodAsync();
}
// library code -- his implementation
public async Task MyMethodAsync()
{
await AnotherOperationAsync();
}
Then the completion of MyMethodAsync will be entrusted to the compiler generated state machine.
Of course, the signaling of completion of AnotherOperationAsync will also be taken care of by the compiler generated state machine, but that is not the point here.
Recall the states inside the MoveNext method indicate the task completion states and in the block inside of MoveNext that invokes the continuation callback, it also calls SetResult on the AsyncXXXMethodBuilder.
When not using the C# Language Support Features
If, however, the implementer of the asynchronous method did not make use of the C# language features, then it is the duty of the implementer to signal the completion of the task by setting the relevant result, exception or cancelled properties on the TaskCompletionSource object.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource<object>();
try
{
AnotherOperation();
tcs.SetResult();
}
catch(Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
If the implementer did not use TPL support or invoked another operation asynchronously using the older .NET API, then too, it is the implementer's responsibility to signal task completion by explicitly setting the status of the task through one of the Try/SetResult/Exception etc. methods.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource...
var autoReseEvent = ...
ThreadPool.QueueUserWorkItem(new WaitCallback(() =>
{
/* Work */
Thread.SpinWait(1000);
tcs.SetResult(...);
autoResetEvent.Set();
};)...;
return tcs.Task;
}
An Ill-Advised Case
The best way to await a task is, of course, to use the await keyword. If, however, when implementing an asynchronous API, the implementer does this:
public Task MyMethodAsync()
{
return Task.Run(...);
}
That would leave the consumer of his API with a sour mouth, I suppose?
Task.Run should only ever be used in a fire and forget scenario where you do not care about the point in time when the task will be completed.
The one exception to this is if you awaited the task returned by the call to Task.Run using the await keyword, like the code snippet shown below, in which case, you would be using the language support as described in the first section.
public async Task MyMethodAsync()
{
await Task.Run(...);
}
I have the following code where I'm trying to make a request to a remote endpoint using HttpClient:
using (var client = new HttpClient())
{
client.BaseAddress = _serviceBaseAddress;
Task<HttpResponseMessage> readResponseTask = client.GetAsync(relativeUri);
readResponseTask.Wait();
using (var response = readResponseTask.Result)
{
if (response.StatusCode == HttpStatusCode.NotFound || !response.IsSuccessStatusCode)
{
return default(TResult);
}
Task<TResult> readContentTask = response.Content.ReadAsAsync<TResult>();
readContentTask.Wait();
TResult value = readContentTask.Result;
return value;
}
}
..and occassionally I would get ThreadAbortException at the readResponseTask.Result like so:
System.Threading.ThreadAbortException: Thread was being aborted. at
System.Threading.Monitor.ObjWait(Boolean exitContext, Int32
millisecondsTimeout, Object obj) at
System.Threading.ManualResetEventSlim.Wait(Int32 millisecondsTimeout,
CancellationToken cancellationToken) at
System.Threading.Tasks.Task.SpinThenBlockingWait(Int32
millisecondsTimeout, CancellationToken cancellationToken) at
System.Threading.Tasks.Task.InternalWait(Int32 millisecondsTimeout,
CancellationToken cancellationToken) at
System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout,
CancellationToken cancellationToken)
Under what circumstance will the .Result throw such an exception? I have tried simulating a timeout on the remote endpoint but I got the exception at the .Wait() instead of .Result. Since the exception happens after .Wait(), I'm assuming the result has already been returned from the remote site but somehow something went wrong when it tries to access the result.
Any clues? Could it be something to do with thread concurrency?
I would get ThreadAbortException at the readResponseTask.Result
No, you don't. The call stack clearly shows that it is in fact the Wait() call that produced the exception. Note the frequent appearance of the word "wait" in the trace.
Hard to see how you got confused. Keep in mind that the Task.Result property getter is very small and is going to be inlined when you run the Release build of your program. So you never can see it back in the stack trace.
Perhaps you'll be ahead by simply removing the Wait() call. It isn't necessary, the Result property getter already performs a wait if necessary.
During Wait(), the thread is aborted from outside. Nobody can tell for sure why.
Enabling network client trace can help detecting the root cause.
First, do not use .*Async() if you're going to immediately call .Wait(). This is poor practice and will more than likely lead to errant results. Instead use the synchronous versions of the calls, client.Get(relativeUri) and the following:
TResult value = response.Content.ReadAs<TResult>();
return value;
If you intend on not taking advantage of the .NET frameworks asynchronous programming model.
But if you would rather take advantage of the asynchronous I/O capabilities, you should do so following the best practices. Use the async/await keywords and make your methods look as though they are synchronous while leveraging the capabilities of the .NET framework's asynchronous keywords.
I can only imagine the entry point to your method looks something like this:
public TResult InvokeClientGet<TResult>(string relativeUri)
{
// ... left out for brevity
}
This is actually preventing you from using the async/await keywords. Instead try the following:
public async Task<TResult> InvokeClientGet<TResult>(string relativeUri)
{
try
{
using (var client = new HttpClient { BaseAddress = _serviceBaseAddress })
{
using (var response = await client.GetAsync(relativeUri))
{
if (response.StatusCode == HttpStatusCode.NotFound ||
!response.IsSuccessStatusCode)
{
return default(TResult);
}
return await response.Content.ReadAsAsync<TResult>();
}
}
catch (Exception ex)
{
// Handle exceptional conditions
}
}
A few words specifically about System.Threading.ThreadAbortException.
When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException. ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. When this exception is raised, the runtime executes all the finally blocks before ending the thread. Because the thread can do an unbounded computation in the finally blocks or call Thread.ResetAbort to cancel the abort, there is no guarantee that the thread will ever end. If you want to wait until the aborted thread has ended, you can call the Thread.Join method. Join is a blocking call that does not return until the thread actually stops executing.
With that being said, if something is calling .Abort() and causing this exception. There isn't much you can do to prevent it. Regardless, try following best practices.
I had the same problem while testing a method via Unit-Tests which was sending Data to a WebService. (ik there are better ways to do that)
The problem was that the Unit-Test called my async method but didn't waited unitl the WebService call had finished. This aborted the WebService call and i got an ThreadAbortException.
[TestMethod]
public void WebServiceTest01(){
BusinessLogic bs = new BusinessLogic();
bs.CallWebService();
}
All I needed to do was to make the Unit-Test wait until the WebService call has finished by adding the keyword await.
[TestMethod]
public void WebServiceTest01(){
BusinessLogic bs = new BusinessLogic();
var result = await bs.CallWebService();
Assert.NotNull(result);
}
I don't see any specific mention either on MSDN or here about how to accomplish this. The use case is somewhat obscure, but still valid I suspect.
var cancel = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => { Task.Delay(1000, cancel.Token).Wait(); }, cancel.Token);
cancel.CancelAfter(100);
task.Wait();
The above code will attempt to cancel a task that contains a detached child delay task after 100 milliseconds, and wait for the task to complete which will generate an AggregateException (due to the cancellation). The problem with this is that the task becomes faulted instead of cancelled. This is expected behaviour because the delay task is not attached to the parent task, even though both share the same cancellation token.
My question relates specifically to how you would go about attaching a Task.Delay to a task that is already running. Is it possible to even do this if you had access to the parent task? If it isn't possible, or not possible without access to the parent task instance what is the proper way to handle this scenario?
The best work around I could come up with was to wrap the delay task's Wait in a try/finally block, and explicitly attempt to bubble up the task cancellation.
try { Task.Delay(1000, cancel.Token).Wait(); } finally { cancel.Token.ThrowIfCancellationRequested(); }
While effective, it doesn't feel quite right, but I'm not sure if there is a better way to accomplish this. The desired outcome is that the parent task goes to Canceled instead of Faulted if cancellation occurs. So if the genesis of the cancellation occurs in a detached child task, the parent task should still transition to Canceled.
NOTE: I left out async/await here on purpose, just because it doesn't appear to change the problem or the result. If that's not the case please provide an example.
So, a task is considered canceled when an OperationCanceledException is thrown and uncaught inside it and its associated CancellationToken is canceled.
In your case the exception being thrown is AggregateException that contains a TaskCanceledException (which is an OperationCanceledException) instead of the TaskCanceledException directly.
There's a simple way to fix that. Instead of synchronously blocking with Task.Wait which wraps any exceptions in an AggregateException wrapper you can use task.GatAwaiter().GetResult(). That is what await uses in async-await. It throws the original exception and if there were multiple ones it throws the first:
var cancel = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => { Task.Delay(1000, cancel.Token).GetAwaiter().GetResult(); }, cancel.Token);
cancel.CancelAfter(100);
task.Wait();
If you would have used async-await you wouldn't have this issue as unlike Task.Wait it throws the TaskCanceledException itself:
var cancel = new CancellationTokenSource();
var task = Task.Run(() => Task.Delay(1000, cancel.Token), cancel.Token);
cancel.CancelAfter(100);
task.Wait();
I assume this is just an example. Real production code shouldn't resembles this as you're blocking synchronously on an asynchronous operation which in turn blocks synchronously on an asynchronous operation.
I'm fairly new to C# and started playing around with the TPL today. I decided to write a modified version of
Task Task.WhenAll as an exercise. I'd like for it to have the following behavior:
Upon finding the first task that has faulted or been canceled, cancel the rest of the tasks instead of waiting for them to finish.
If the task faulted, the returned task should have the right exception set (i.e no swallowing by continuation and replacing with OperationCancelledException())
No async in the method signature (want to avoid bubbling it up).
I came up with the following crazy/stupid piece of code that doesn't work and I am having a hard time visualizing what's going on. I can't imagine any blocking going on and what i envisioned happening was a chain of tasks each waiting on the rest for completion. Could someone explain what's going on?
I wouldn't have it in production code and this is just to test my fundamentals. I realize an easier way of doing this would be to do a Task.WhenAll and have the tasks in the list themselves have continuations that do the cancellation on failure.
public static Task WhenAllError(List<Task> tasks, CancellationToken ct)
{
var tcs = new TaskCompletionSource<object>();
return Task.WhenAny(tasks).ContinueWith<Task>((t) =>
{
if (tasks.Count == 0)
{
tcs.SetResult(null);
return tcs.Task;
}
if (t.IsFaulted)
{
Console.WriteLine("Task faulted. Cancelling other tasks: {0}", t.Id);
cts.Cancel();
// Make sure the tasks are cancelled if necessary
tcs.SetException(t.Exception);
return tcs.Task;
}
// Similarly handle Cancelled
tasks.Remove(t);
return WhenAllError(tasks, ct);
}).Unwrap();
}
The CancellationToken class has no Cancel method. You need a CancellationTokenSource to be able to cancel the CancellationToken.
Similarly to affect the outcome of a task you need a TaskCompletionSource you can't safely
cancel already running tasks. See this post
Can someone please explain to me to the usage of the Task.Wait(CancellationToken) overload? MSDN does say much about it...
This is how I usually handle task cancellations:
var source = new CancellationTokenSource();
var task = Task.Factory.StartNew(() =>
{
while (true)
{
source.Token.ThrowIfCancellationRequested();
}
}, source.Token);
try
{
task.Wait();
}
catch (AggregateException exc)
{
exc.Flatten().Handle(e => e is OperationCanceledException);
}
So when is it useful to pass the token to the Wait method?
Consider the case where you want to cancel waiting for the task, without actually cancelling the task itself... either because the task doesn't handle cancellation itself, or because you actually want to keep going with the task, but (say) respond to the user with "This is taking a while... but it's still in progress. It's safe to close your browser." (Or whatever.)
Found this in a Microsoft white paper:
It is also interesting to note the existence of an overload for Task.Wait() that takes a CancellationToken with the signature Task.Wait(CancellationToken). This overload takes a token so that the wait can be canceled; this overload has nothing to do with canceling the task, but rather it can cause the wait to return prematurely. If Task.Wait(ct) is used and the wait is interrupted because it detects the token has been signaled, then an OperationCanceledException(ct) will be thrown to indicate that the wait operation was canceled.