This notifies of an unhandled exception:
new Thread(_ => { throw new Exception(); }).Start();
This does not (at least until you wait/retrieve the result):
Task.Factory.StartNew(() =>
{
throw new Exception();
});
Why? What has happened to the thread on which the exception was thrown? Does it die?
This is a problem where you run a task but don't need its result, or need to wait on it, like this:
_operationQueue = new BlockingCollection<Operation>();
Task.Factory.StartNew(() =>
{
foreach (var item in _operationQueue.GetConsumingEnumerable())
{
// do something that throws
}
}, TaskCreationOptions.LongRunning);
In this case, what state is the _operationQueue
left in?
I know I can use a Continuation with TaskContinuationOptions.OnlyOnFaulted, can you just resume processing?
Well, what are you assuming should happen instead? Are you thinking that whenever an exception is thrown in another thread it should immediately propagate to the thread that started that task? I strongly disagree. First off, the code in the calling thread would then be forced to abort the operation it's in the middle of, and that's rather likely to cause significant problems. Just look into all of the posts surrounding Thread.Abort
to see all of the very significant problems that arise when you allow an exception to be thrown at some arbitrary point in a program's execution instead of at certain known points.
If you're suggesting that the entire program should crash when a task's code throws an exception, then I'd say that by and large that's simply not desirable. In the rare case that it is, you can (rather easily) create a continuation on the task that does end the entire process if the task is faulted. I've yet to to need to create such a continuation myself though. If the system were designed to bring down the process when a task threw an exception then getting the opposite behavior wouldn't be nearly as easy.
What has happened to the thread on which the exception was thrown? Does it die?
If the exception is caught then execution continues after the catch; if it propagates through the entire call stack then the exception will be caught by code within the Task
framework which wraps the exception and makes it available to continuations.
In this case, what state is the _operationQueue left in?
It's a perfectly fine queue, that has had 1..N items removed from it. If the body of the loop always throws then one item will have been taken from it. If it only sometimes throws, then some number of items will be taken from it. The remaining items are still in the queue and can be removed by any other thread with access to it. If the queue is no longer accessible then it would become eligible for garbage collection.
I know I can use a Continuation with TaskContinuationOptions.OnlyOnFaulted, can you just resume processing?
The calling thread can; sure. The task itself would only be able to continue by having a try/catch
within it's delegate. If the exception has been thrown to the point that the task is faulted nothing would allow that task to continue executing.
The exception in the task is caught by the TaskScheduler
. If you never want to observe the result of a task, but would like to be notified on unhandled exceptions in tasks, there is the TaskScheduler.UnobservedTaskException
event. Note that this event does not fire immediately, but upon finalization of the Task
if the exception has never been retrieved. In .Net 4, unobserved task exceptions were rethrown and became unhandled exceptions that ended the process, but this was changed in .Net 4.5.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With