Task and exception silence - c#

Why exceptions thrown within a task are silent exception and you never know if a certain exception has been thrown
try
{
Task task = new Task(
() => {
throw null;
}
);
task.Start();
}
catch
{
Console.WriteLine("Exception");
}
the program run successfully in a complete silence!
where the behavior of threads is different
try
{
Thread thread = new Thread(
() => {
throw null;
}
);
thread .Start();
}
catch
{
Console.WriteLine("Exception");
}
a null pointer exception will be thrown in this case.
What is the difference?

The behaviour of that scenario depends on what framework you have; in 4.0, you actually need to be careful - if you don't handle TaskScheduler.UnobservedTaskException, it will error later when it gets collected/finalized, and will kill your process.
TaskScheduler.UnobservedTaskException += (sender, args) =>
{
Trace.WriteLine(args.Exception.Message); // somebody forgot to check!
args.SetObserved();
};
This changes in 4.5, IIRC.
To check the outcome of a Task that might fail, you could register a continuation - i.e. call ContinueWith and check the result's exception. Alternatively, accessing the .Result of the task (which would also do an implicit Wait()) will re-surface the exception that happened. It is good to observe the result of a task, as that clears the finalization flag, meaning it can be collected more cheaply.

No, tasks are not threads. Tasks represent a high level abstraction - they are a unit of work that is inherently parallelisable. Threads run units of work.
In your first example, you create a unit of work and then tell it to run itself (how it does so is an implementation detail of Task). Whereas in your second example you explicitly schedule a unit of work (it would appear in a different manner to the implementation of Task).

The following assumes .NET 4.0, and the using the default TaskScheduler.
First of all notice that the exceptions are raised inside the delegates you pass, so they are raised in a different thread, not in the one you (logically) are doing your catch. So somehow the exception must be propagated from the thread that executes your delegate / lambda code to the one that started the thread/task.
Note that for Task, I think that the library can also choose not to run it on it's own thread, but rather on the calling thread (but I'm not sure if that was only true for Parallel.ForEach, etc. and not for a "naked" Task object).
For that two happen, two things must be fulfilled:
The calling thread is still active. Otherwise there is nothing left that could actually perform the catch.
The exception that was caused in the thread/task must somehow be preserved and reraised for you to catch it.
Having that said, both of your examples don't wait for the thread/task to finish. In the first example you're missing a task.Wait() (or similar) and in the second a thread.Join(). Depending on your test codes timing behavior this may mean that you may never be able to observe the exception from the thread/task (item 1 above).
Even if you add the two calls this is what happens for me (again .NET 4.0):
Task example: the call to task.Wait() actually reraises the exception originally left unhandled in the task's delegate (this is what the TPL will do for you internally), it does wrap it inside a System.AggregateException, which you could/would see if you'd use something more precise then a flat "catch-all".
Thread example: the exception raised by the delegate remains unhandled and your application exits (unless you do anything to deal with unhandled exceptions differently)
In other words I would have the examples as follows:
// Thread example
var thread = new Thread(() => { throw null; });
thread.Start();
thread.Join();
// Should never reach here, depending on timing sometimes not even
// until the Join() call. The process terminates as soon as the other
// thread runs the "throw null" code - which can logically happen somewhere
// after the "start" of the "Start()" call.
// Task example
try
{
var task = new Task(() => { throw null; });
task.Start();
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine("Exception: " + ex);
}

I think you are not getting exception in case of Task because you are not waiting for exception in the main thread. You are just continuing. Put task.Wait() and you will get the exception in main thread.

Related

Catching Exceptions INSIDE a delegate in a generic fashion

I need help identifying a generic way of catching exceptions that are thrown from within a delegate when that delegate contains a Task.Run that is throwing an exception. Currently, when I invoke a delegate (in this case a func) that is passed into another "master" method and an exception is thrown from within a Task.Run in the delegate, the exception is not caught with a try/catch in the code surrounding the invocation. The following simplified example shows the exceptions inside the delegate being caught by the try/catch inside the delegate but being "lost" elsewhere:
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += (s, e) => CurrentDomain_UnhandledException();
TaskScheduler.UnobservedTaskException += (s, e) => CurrentDomain_UnhandledException();
HandledDelegate(() => Task.Run(() =>
{
try
{
Console.WriteLine("Executed");
throw new Exception($"Caught");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw new Exception($"Caught Again");
}
}
));
}
private static void CurrentDomain_UnhandledException()
{
Console.WriteLine("Unhandled Exception Occurred.");
}
public static void HandledDelegate(Action a)
{
try
{
a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
Thread.Sleep(10000);
}
And the following example shows the exception not being caught within the try/catch around the invoke, and bubbling up to the app domain as an unhandled exception.
public static void Main()
{
AppDomain.CurrentDomain.UnhandledException += (s, e) => Console.WriteLine("Unhandled Exception");
HandleDelegateEx(async () => await Task.Run(() => throw new Exception("test")));
Thread.Sleep(1000);
}
public static void HandleDelegateEx(Action a)
{
try
{
a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This last one is most like my current code which I need to fix. The delegates often Task the code off on a background thread and don't handle any errors (expecting them to be caught by where the delegate is invoked.
This code is used throughout the app in hundreds of locations, and few, if any, catch exceptions within the delegate (as other programmers erroneously thought that exceptions thrown by the delegate would be caught). Is there any way to catch exceptions thrown from inside these delegates without massively refactoring each and every delegate to catch exceptions?
The issue is not connected to delegate itself. In your fiddle you don't wait for Task returned by delegate to complete. Basically the delegate will return Task and the method will continue. In your original code in question:
try
{
// Execute the requested action.
retval = clientOperation.Invoke(remoteObj);
}
catch(ex)
{
// log here.
}
finally
{
CloseChannel(remoteObj);
}
It will jump straight to finally clause and attempt to close connection. You need to handle Func's returning tasks separately:
public void HandleDelegateEx<T>(Func<T> a)
{
try
{
a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public async Task HandleDelegateExAsync<T>(Func<Task<T>> a)
{
try
{
await a.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
HandleDelegateEx<int>(() => throw new Exception("test")); // prints "test"
Func<Task<int>> func = () => Task.FromException<int>(new Exception("test async"));
HandleDelegateEx(func); // does not print anything
await HandleDelegateExAsync(func); // prints "test async"
You can get the same behavior without delegates:
Task task = null;
try
{
task = Task.FromException(new Exception("test async"));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // does not go here
}
await task; // throws here
In order for your exceptions to be observed, you would either have to await the returned task as Guru Stron suggests (implying a massive refactoring I guess). Or somehow adding Wait() to the result of the Task.Run() call, but this will block the calling thread (I'm assuming this is the UI thread) while the background thread churns the delegate - neglecting the benefit of the task being a background thread in the first place.
So, most probably, here is the crux of the problem: you need to wait for the background Task to finish so you can observe any possible exceptions, without blocking the UI thread, and do this while modifying the least amount of code.
I'm assuming your application is either Windows Forms or WPF.
For the first problem -waiting for the task to finish without blocking the UI thread-, I would turn to the old (and very frowned upon) Application.DoEvents() (or its equivalent in WPF, second answer). This is strongly discouraged these days, but I guess it is much better than ignoring exceptions that should have been handled (and keep in mind this was valid and in fact, the only way of keeping a responsive UI in the 16-bit era).
Instead of adding Wait(), to the background task, I would wait for its completion with the following loop:
while( !backgroundTask.IsCompleted ) {
Application.DoEvents(); // keep UI responsive while background task finishes
}
Now, the second problem, we would have to somehow inject this loop right after the background task is queued in the thread pool, and as you describe, this occurs in potentially hundreds of places.
Here I would try using Harmony, a very powerful dynamic IL patching tool. This tool allows you to target a method and piggyback a prefix and/or a postfix method. The prefix method will be called automatically before the target method is called, and the postfix method will be called after the target method is called.
The patching would look something like this:
// Must be called once before the target delegates are executed
private void MyClass.Patch() {
var original = typeof(Task).GetMethod("Run", ...); // I'm omitting the code that would select the (Action action) overload
var postfix = typeof(MyClass).GetMethod("WaitWithResponsiveUI", ...);
harmony.Patch(original, postfix: new HarmonyMethod(postfix));
}
private void MyClass.WaitWithResponsiveUI(ref Action __result) {
// __result contains the original Task returned by Task.Run()
while( !__result.IsCompleted ) {
Application.DoEvents(); // keep UI responsive while background task finishes
}
__result.Wait(); // Any exceptions produced inside the delegate should be rethrown at this moment, and they should be trappable by the code that invoked the delegate
}
Of course, this has the disadvantage that every Task.Run(Action action) called after patching would now wait until the task is done, globally, and this might not be desirable for every call.
EDIT: In defense of Application.DoEvents();
Here is a very well written answer detailing all the potential pitfalls of using Application.DoEvents(). These pitfalls are real and should be considered.
However, one aspect I strongly disagree is the assertion that the async-await mechanism is a safe way to avoid all these problems. That is simply not true.
When a UI event handler finds an await, it basically sets up a continuation that will be able to resume the event handling in the future, and immediately returns, giving the application's message pump a chance to continue running (basically what Application.DoEvents(), with the difference that the latter will return once the event queue is empty).
When the awaited operation completes, the continuation IS enqueued as another event into the Message event queue, so it won't resume execution until the message pump has handled all the events that have been posted before. My point being - While the operation is awaited, messages ARE being processed and you still need to protect your application from any reentrancy pitfalls manually. See here: Handling Reentrancy in Async Apps (C#).
Another pitfall exclusive to async-await UI code is that some components (DataGridView comes to mind) pass some of their event arguments to their handlers in objects that implement IDisposable. The component raises the event, and disposes the arguments as soon as the event handler returns. In async code, this return to the caller will happen when the first await in the handler code is reached. This has the effect that when the awaited code resumes, accessing the event-arguments object throws an ObjectDisposedException, as it has already been disposed by the raising component itself!
The "false multithreading" aspect is already being handled here, as the work is truly being offloaded to the thread pool.
So, in my opinion, the only real problem to address is the potential stack-overflow problem, that could be addressed by reentrancy avoidance measures that have to be accounted for in the first place, whether you use async/await or DoEvents().

Working with Task Parallelism and processes in C#

I am trying to understand data parallelism and processes in C#(Reference) and am getting a bit confused by the behavior. I may be missing some really basic concept , but it would be great if anyone could explain this
So I have the following code :-
private static void Process()
{
Process _process = new Process();
_process.StartInfo.FileName = "C:\\Windows\\notepad.exe";
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.RedirectStandardOutput = true;
// Start the process
_process.Start();
_process.BeginOutputReadLine();
Task task = Task.Factory.StartNew(() => MonitorProcess());
Console.WriteLine("Main ");
}
private static void MonitorProcess()
{
Console.WriteLine("Inside Monitor");
string x = null;
x = x.Trim();
}
Now my expectation is that "Main" should never be printed to the console since there is a null reference exception in the MonitorProcess method . I don't want to use task.Wait() to catch and throw the exception since that will wait for the task to complete.
So why does this happen and how can i get around this so that code execution is stopped at the exception in the MonitorProcess method ?
A task is run in a seperate thread (one from the thread pool). The exception isn't thrown in the main thread, so why should the main thread stop?
Since the two threads execute in parallel, it might even be possible for your Process method to print (and return) before the exception is even thrown in the MonitorProcess method.
If you want your main thread to stop, you have to propagate the exception to it. You can find a few examples how to do this here: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was
But doing this without waiting in the main thread will still not stop the main thread from printing because, as I already said, that code might have already been executed.

C# - Thread Abort Exception (Thread Abort Exception) rethrowing itself

I have the current code:
class Program
{
private static void Main()
{
while (true)
{
try
{
Thread.CurrentThread.Abort();
}
catch (ThreadAbortException)
{
Console.WriteLine("Abort!");
Thread.ResetAbort();
}
Console.WriteLine("now waiting");
Console.ReadKey();
}
}
}
Now I know the method ResetAbort is supposed to prevent the ThreadAbortException from continue to re-throw itself even when a catch statement is catching it, but my question is this:
If anyone can use the ResetAbort method, then what's the point of the exception specially re-throw itself?
the user can just do
catch (ThreadAbortException ex)
{
Console.WriteLine("Abort!");
throw ex;
}
Thread.ResetAbort() is not meant for common use. It can cause undesired behavior if you don't understand why the thead abort happened. Because of this, and probably to make ASP.NETs stable in shared hosting environments, the SecurityPermissionFlag.ControlThread permission is required to call Thread.ResetAbort()
MSDN Link
The point of ThreadAbortException rethrowing itself is to make sure the thread terminates unless the user explicitly calls ResetAbort.
Let me explain:
try
{
// ... Thread abort happens somewhere in here
}
catch (Exception ex)
{
_log.Error(ex);
}
Here you have a typical example of code that ensures no exception propagates from inside the try block. I know that catching Exception is bad practice, but code like this exists nonetheless.
If you call Abort while the thread is inside the try block you still want it to abort. You just can't rely on users writing this sort of code everywhere:
try
{
// ... Thread abort happens somewhere in here
}
catch (ThreadAbortException)
{
throw; // No, you'll NEVER see code like this in real life
}
catch (Exception ex)
{
_log.Error(ex);
}
So, in order to provide a sort of reliable Abort, the exception has to be automatically rethrown, or it may easily get discarded by accident.
ResetAbort is meant for the very rare case when you specifically detect a thread abort, and you exactly know why it happenned, and you want to prevent it.
Needless to say, the use cases for this are extremely rare. Thread aborts are treated by the runtime in a very special way, and you should avoid them whenever possible. Heck, they even aren't reliable as you pointed out, and all this discussion is ignoring CERs which make matters worse.
The point is to define a default behavior in which the exception is rethrown, seeing as how there is a remote chance that the user will have any point of continuing the thread.
Moreover, ResetAbort has a security demand and can not be called by any code.
Because Aborting a thread doesn't necessarily mean an exception will be thrown. For the Abort Procedure the catch (ThreadAbortException) block is just another critical region of code. It only gives us a thread safe and convenient way of detecting if the current thread is being aborted (and maybe with some state being passed too) in case we want to do something special. Other than that, it is like any other critical region (like a finally block) where it will terminate the thread after its execution.
At the same time, in your example Abort is called synchronously (which is actually safe to do) and in that case it is very similar to throwing an exception. Things only get interesting and dangerous when it's called asynchronously from another thread, due to the Abort procedure being more complicated than just throwing an exception: In essence, first, thread is marked as being aborted, then critical code regions (for example finally blocks) are executed and only then the exception is thrown, if the AbortRequested flag is still set on the thread, and so on.
Code below illustrates this fact by recovering an aborted thread without catching any exceptions:
var inFinally = new ManualResetEvent(false);
var abortCalled = new ManualResetEvent(false);
var t = new Thread(_ =>
{
Console.WriteLine("Thread started..");
try
{
}
finally
{
inFinally.Set();
abortCalled.WaitOne();
Console.WriteLine(" ThreadState (before): " + Thread.CurrentThread.ThreadState);
// This isn't thread safe, and ugly?
if ((Thread.CurrentThread.ThreadState & ThreadState.AbortRequested) != 0)
{
Thread.ResetAbort();
}
Console.WriteLine(" ThreadState (after): " + Thread.CurrentThread.ThreadState);
}
Console.WriteLine("Executed because we called Thread.ResetAbort()");
});
t.Start();
inFinally.WaitOne();
// Call from another thread because Abort()
// blocks while in finally block
ThreadPool.QueueUserWorkItem(_ => t.Abort());
while ((t.ThreadState & ThreadState.AbortRequested) == 0)
{
Thread.Sleep(1);
}
abortCalled.Set();
Console.ReadLine();
// Output:
//--------------------------------------------------
// Thread started..
// ThreadState (before): AbortRequested
// ThreadState (after): Running
// Executed because we called Thread.ResetAbort()
Now, I must be honest: I am not entirely sure how one could use this feature and create something useful. But it sounds like Thread.Abort API was (probably still is, I don't know) used to facilitate thread and AppDomain reuse in frameworks like ASP.NET.
In one of Joe Duffy's Blog entries, Managed code and asynchronous exception hardening, he talks about ResetAbort and the Abort API:
Some framework infrastructure, most notably ASP.NET, even aborts individual threads
routinely without unloading the domain. They backstop the ThreadAbortExceptions, call
ResetAbort on the thread and reuse it or return it to the CLR ThreadPool.
I can imagine it can be used in a framework to reuse the managed threads, reducing the overhead. However, the problems (bad thread synchronization design, bad exception handling, dead locks and so on) introduced in user code, by this easily misunderstood API, rendered the Abort and ResetAbort calls more troublesome than useful.

Why doesn't this exception get thrown?

I use a set of tasks at times, and in order to make sure they are all awaited I use this approach:
public async Task ReleaseAsync(params Task[] TaskArray)
{
var tasks = new HashSet<Task>(TaskArray);
while (tasks.Any()) tasks.Remove(await Task.WhenAny(tasks));
}
and then call it like this:
await ReleaseAsync(task1, task2, task3);
//or
await ReleaseAsync(tasks.ToArray());
However, recently I have been noticing some strange behavior and set to see if there was a problem with the ReleaseAsync method. I managed to narrow it down to this simple demo, it runs in linqpad if you include System.Threading.Tasks. It will also work slightly modified in a console app or in an asp.net mvc controller.
async void Main()
{
Task[] TaskArray = new Task[]{run()};
var tasks = new HashSet<Task>(TaskArray);
while (tasks.Any<Task>()) tasks.Remove(await Task.WhenAny(tasks));
}
public async Task<int> run()
{
return await Task.Run(() => {
Console.WriteLine("started");
throw new Exception("broke");
Console.WriteLine("complete");
return 5;
});
}
What I don't understand is why the Exception never shows up anywhere. I would have figured that if the Tasks with the exception were awaited, it would throw. I was able to confirm this by replacing the while loop with a simple for each like this:
foreach( var task in TaskArray )
{
await task;//this will throw the exception properly
}
My question is, why doesn't the shown example throw the exception properly (it never shows up anywhere).
TL;DR: run() throws the exception, but you're awaiting WhenAny(), which doesn't throw an exception itself.
The MSDN documentation for WhenAny states:
The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state.
Essentially what is happening is that the task returned by WhenAny simply swallows the faulted task. It only cares about the fact that the task is finished, not that it has successfully completed. When you await the task, it simply completes without error, because it is the internal task that has faulted, and not the one you're awaiting.
A Task not being awaited or not using its Wait() or Result() method, will swallow the exception by default. This behavior can be modified back to the way it was done in .NET 4.0 by crashing the running process once the Task was GC'd. You can set it in your app.config as follows:
<configuration>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
A quote from this blog post by the Parallel Programming team in Microsoft:
Those of you familiar with Tasks in .NET 4 will know that the TPL has the notion of “unobserved” exceptions. This is a compromise between two competing design goals in TPL: to support marshaling unhandled exceptions from the asynchronous operation to the code that consumes its completion/output, and to follow standard .NET exception escalation policies for exceptions not handled by the application’s code. Ever since .NET 2.0, exceptions that go unhandled on newly created threads, in ThreadPool work items, and the like all result in the default exception escalation behavior, which is for the process to crash. This is typically desirable, as exceptions indicate something has gone wrong, and crashing helps developers to immediately identify that the application has entered an unreliable state. Ideally, tasks would follow this same behavior. However, tasks are used to represent asynchronous operations with which code later joins, and if those asynchronous operations incur exceptions, those exceptions should be marshaled over to where the joining code is running and consuming the results of the asynchronous operation. That inherently means that TPL needs to backstop these exceptions and hold on to them until such time that they can be thrown again when the consuming code accesses the task. Since that prevents the default escalation policy, .NET 4 applied the notion of “unobserved” exceptions to complement the notion of “unhandled” exceptions. An “unobserved” exception is one that’s stored into the task but then never looked at in any way by the consuming code. There are many ways of observing the exception, including Wait()’ing on the Task, accessing a Task’s Result, looking at the Task’s Exception property, and so on. If code never observes a Task’s exception, then when the Task goes away, the TaskScheduler.UnobservedTaskException gets raised, giving the application one more opportunity to “observe” the exception. And if the exception still remains unobserved, the exception escalation policy is then enabled by the exception going unhandled on the finalizer thread.
From the comment:
these [tasks] were tied to managed resources and I wanted to release them when
they became available instead of waiting for all of them to complete
and then releasing.
Using a helper async void method may give you the desired behavior for both removing the finished tasks from the list and immediately throwing unobserved exceptions:
public static class TaskExt
{
public static async void Observe<TResult>(Task<TResult> task)
{
await task;
}
public static async Task<TResult> WithObservation(Task<TResult> task)
{
try
{
return await task;
}
catch (Exception ex)
{
// Handle ex
// ...
// Or, observe and re-throw
task.Observe(); // do this if you want to throw immediately
throw;
}
}
}
Then your code might look like this (untested):
async void Main()
{
Task[] TaskArray = new Task[] { run().WithObservation() };
var tasks = new HashSet<Task>(TaskArray);
while (tasks.Any<Task>()) tasks.Remove(await Task.WhenAny(tasks));
}
.Observe() will re-throw the task's exception immediately "out-of-band", using SynchronizationContext.Post if the calling thread has a synchronization context, or using ThreadPool.QueueUserWorkItem otherwise. You can handle such "out-of-band" exceptions with AppDomain.CurrentDomain.UnhandledException).
I described this in more details here:
TAP global exception handler

Where should my Try Catch block be when running a thread?

Take this thread:
Thread thread = new Thread(delegate()
{
//Code
});
thread.Start();
Should it be around the thread.Start(); or inside:
Thread thread = new Thread(delegate()
{
try
{
//Code
}
catch (Exception)
{
//Code
}
});
it is completely different to put then inside or outside.
If you put them around the thread.Start() call, you can detect (according to this page: http://msdn.microsoft.com/en-us/library/system.threading.thread.start(v=vs.71).aspx)
ThreadStateException The thread has already been started.
SecurityException The caller does not have the appropriate SecurityPermission.
OutOfMemoryException There is not enough memory available to start this thread.
NullReferenceException This method was invoked on a thread reference that is a null reference (Nothing in Visual Basic).
If you put it inside, you will detect exception inside the code you will run in your thread. So any kind of exception you want.
The exceptions pertaining the logic you have in the delegate should be handled inside the delegate.
thread.Start() itself can only throw ThreadStateException or OutOfMemoryException.
Preventing silent thred termination
It explains to place the try catch inside of the delegate. It also talks about doing your finnally clean up if needed.
If, as you mention above, the error is in the delegate code, then put the try-catch in there and log the exception. Alternatively, if you want that exception to be passed back to the original thread use an asynchronous delegate (calling EndInvoke will re-raise the exception to the calling thread or use Background worker and subscribe to RunWorkerCompleted event (this has error property in event args).

Categories

Resources