I have an application with Start and Stop buttons, and a thread that is ran in the background after pressing Start. I use MVC and TPL for that.
How can I handle exception in the TPL, as I never invoke Wait() method? On any exception I need to show Error message box, and this box should be shown after it was thrown right away.
I have always single thread in the background, so you cannot press Start without previously Stopping the thread.
I'm looking for some good patterns or best practice. I have an idea to place try..catch inside thread, and invoke an event on each catch, but I'm not sure is such approach is good architecture decision
If you're using Tasks, you can add a continuation that only runs if an exception is thrown. You can also tell it to run on your UI thread so you can use your UI controls:
task.ContinueWith(
t => { var x = t.Exception; ...handle exception... },
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
TaskScheduler.FromCurrentSynchronizationContext()
);
At a high level the Wait method simply takes the Exception which occurred in the background thread, wraps it in another Exception type and rethrows it. So you can observe the original Exception on the background thread with a standard try / catch block surrounding your logic code.
There's nothing wrong with handling the exception right in the Task (on the background thread). If you need to show UI in the event of an exception, you can use the Dispatcher (assuming you're using wpf or silverlight): http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
Related
I am trying to understand exception handling in TPL.
The following code seems to swallow exceptions:
var processor = new ActionBlock<int>((id) => SomeAction(id), new ExecutionDataflowBlockOptions { ... });
async Task SomeAction(int merchantID)
{
//Exception producing code
...
}
And listening to TaskScheduler.UnobservedTaskException events does not receive anything either.
So, does this mean the action block does a try-catch in itself when running the actions?
Is there any official documentation of this somewhere?
Update
The exception handling behavior of DataFlow blocks is explained in Exception Handling in TPL DataFlow Networks
**Original
This code doesn't swallow exceptions. If you await the block to complete with await processor.Completion you'll get the exception. If you use a loop to pump messages to the block before calling Complete() you need a way to stop the loop too. One way to do it is to use a CancellationTokenSource and signal it in case of exception:
void SomeAction(int i,CancellationTokenSource cts)
{
try
{
...
}
catch(Exception exc)
{
//Log the error then
cts.Cancel();
//Optionally throw
}
}
The posting code doesn't have to change all that much, it only needs to check whether
var cts=new CancellationTokenSource();
var token=cts.Token;
var dopOptions=new new ExecutionDataflowBlockOptions {
MaxDegreeOfParallelism=10,
CancellationToken=token
};
var block= new ActioBlock<int>(i=>SomeAction(i,cts),dopOptions);
while(!token.IsCancellationRequested && someCondition)
{
block.Post(...);
}
block.Complete();
await block.Completion;
When the action throws, the token is signaled and the block ends. If the exception is rethrown by the action, it will be rethrown by await block.Completion as well.
If that seems convoluted, it's because that's somewhat of an edge case for blocks. DataFlow is used to create pipelines or networks of blocks.
The general case
The name Dataflow is significant.
Instead of building a program by using methods that call each other, you have processing blocks that pass messages to each other. There's no parent method to receive results and exceptions. The pipeline of blocks remains active to receive and process messages indefinitely, until some external controller tells it to stop, eg by calling Complete on the head block, or signaling the CancellationToken passed to each block.
A block shouldn't allow unhandled exceptions to occur, even if it's a standalone ActionBlock. As you saw, unless you've already called Complete() and await Completion, you won't get the exception.
When an unhandled exception occurs inside a block, the block enters the faulted state. That state propagates to all downstream blocks that are linked with the PropagateCompletion option. Upstream blocks aren't affected, which means they may keep working, storing messages in their output buffers until the process runs out of memory, or deadlocks because it receives no responses from the blocks.
Proper Failure Handling
The block should catch exceptions and decide what to do, based on the application's logic:
Log it and keep processing. That's not that different from how web application's work - an exception during a request doesn't bring down the server.
Send an error message to another block, explicitly. This works but this type of hard-coding isn't very dataflow-ish.
Use message types with some kind of error indicator. Perhaps a Success flag, perhaps an Envelope<TMessage> object that contains either a message or an error.
Gracefully cancel the entire pipeline, by signaling all blocks to cancel by signaling the CancellationTokenSource used to produce the CancellationTokens used by all blocks. That's the equivalent of throw in a common program.
#3 is the most versatile option. Downstream blocks can inspect the Envelope and ignore or propagate failed messages without processing. Essentially, failed messages bypass downstream blocks.
Another option is to use the predicate parameter in LinkTo and send failed messages to a logger block and successful messages to the next downstream block. In complex scenarios, this could be used to eg retry some operations and send the result downstream.
These concepts, and the image, come from Scott Wlaschin's Railway Oriented Programming
The TaskScheduler.UnobservedTaskException event is not a reliable/deterministic way to handle exceptions of faulted tasks, because it's delayed until the faulted task is cleaned up by the garbage collector. And this may happen long after the error occurred.
The only type of exception that is swallowed by the dataflow blocks is the OperationCanceledException (AFAIK for non-documented reasons). All other exceptions result to the block transitioning to a faulted state. A faulted block has its Completion property (which is a Task) faulted as well (processor.Completion.IsFaulted == true). You can attach a continuation to the Completion property, to receive a notification when a block fails. For example you could ensure that an exception will not pass unnoticed, by simply crashing the process:
processor.Completion.ContinueWith(t =>
{
ThreadPool.QueueUserWorkItem(_ => throw t.Exception);
}, default, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
This works because throwing an unhandled exception on the ThreadPool causes the application to terminate (after raising the AppDomain.CurrentDomain.UnhandledException event).
If your application has a GUI (WinForms/WPF etc), then you could throw the exception on the UI thread, that allows more graceful error handling:
var uiContext = SynchronizationContext.Current;
processor.Completion.ContinueWith(t =>
{
uiContext.Post(_ => throw t.Exception, null);
}, default, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
This will raise the Application.ThreadException event in WinForms.
I have a System.Timers.Timer timer which it's AutoReset is set to false. I use a try/finally to insure I Start the timer at the end of it's callback (I use the timer this way to prevent overlapping of callback execution). Code:
// inside timer call back
try
{
// Do something
}
finally
{
timer.Start(); // Is this line always executed?
}
My question is what happens if the executing thread is Aborted? Does the finally section still executed or there's no thread to run that part?
The official source...
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.
Read more about it on MSDN.
Yes, that line will always be executed and the abort blocked until the code in the finally clause finishes.
Quoth the documentation (empahsis mine):
When this method is invoked on a thread, the system throws a ThreadAbortException in the thread to abort it. ThreadAbortException is a special exception that can be caught by application code, but is re-thrown at the end of the catch block unless ResetAbort is called. ResetAbort cancels the request to abort, and prevents the ThreadAbortException from terminating the thread. Unexecuted finally blocks are executed before the thread is aborted.
The thread is not guaranteed to abort immediately, or at all. This situation can occur if a thread does an unbounded amount of computation in the finally blocks that are called as part of the abort procedure, thereby indefinitely delaying the abort. To wait until a thread has aborted, you can call the Join method on the thread after calling the Abort method, but there is no guarantee that the wait will end.
So the answer is yes, the finally blocks will be executed.
Yes the finally will always be used no matter how it exits from try,
Whereas catch is used to handle exceptions that occur in a statement block,
finally is used to guarantee a statement block of code executes regardless
of how the preceding try block is exited.
Read more it on MSDN.
if the thread has already been aborted, the catch block and the finally block can continue to execute.
Please refer this link to get a clear picture on how it is handled in system.threading class
Plumbing the Depths of the ThreadAbortException
C#, using VS2010 and I've got something that makes no sense.
At startup my program needs to load several hundred k from text files. After ensuring the loading code was working fine I threw it in a background thread. So long as this is run from within the IDE everything's fine but when it's run standalone the thread says it's done when it isn't. This of course goes boom.
The trigger code:
BackgroundWorker Background = new BackgroundWorker();
Background.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DatabaseLoaded);
Background.DoWork += new DoWorkEventHandler(delegate { Database.Load(); });
Background.RunWorkerAsync();
and the stuff that's going boom is in DatabaseLoaded().
I put some messageboxes to trace what's going on: The first and last lines of the Load() method and the first line of DatabaseLoaded().
In the IDE this triggers as I expect: Load() beginning, Load() done, DatabaseLoaded(). However, when run standalone I get Load() beginning, DatabaseLoaded() and then the unhandled exception box (the loader hasn't even gotten to build empty tables, let alone fill them.)
Am I nuts or is Microsoft?
RunWorkerCompleted will be invoked in case of an error (such as an unhandled exception in Database.Load()). Check the Error property of the RunWorkerCompletedEventArgs.
There's probably an exception thrown from Database.Load(). BackgroundWorker catches any unhandled exception before triggering the RunWorkerCompleted event. Check the RunWorkerCompletedEventArgs.Error property in DatabaseLoaded.
I was unable to find an answer to this question anywhere...
What happens with the exceptions thrown in the callback method for System.Threading.Timer, (or in the event handler for System.Timers.Timer). Is the exception propagated to the thread on which the timer was created or is the exception lost?
What are the side-effects of throwing an exception within the timer's callback functions?
What would be the right way to signalize to the timer's creation thread that the exception in the worker thread (callback method) has been thrown?
Thanks for your time.
The exception is not passed back to the calling thread. If you want it to be, you can add a catch block and figure out a way to signal the calling thread. If the calling thread is a WinForms or WPF UI thread, you can use the SynchronizationContext class to pass a call to the UI thread. Otherwise, you could use a thread-safe queue (or a sync lock) and check it periodically in the other thread.
System.Timers.Timer will silently swallow exceptions and continue the timer (although this is subject to change in future versions of the framework); System.Threading.Timer will terminate the program.
I don't know what the best option is, but when I'm using a callback timer I'm normally throwing exceptions and letting them bubble up to the main callback routine, where I handle them gracefully. The thread continues to run on the timer as it should.
Unhandled exceptions in the thread (System.Threading.Timer) will stop your entire program.
I dont know if it is a best solution, but what I did was a small workaround. My calling thread has subscribed to an event for catching exceptions from across the threads. So when exception occurs in some thread, say in TimerElapsed event, then form the catch block I raise the event passing exception object as an argument to the event.
EventHolderCallingClass: It must define delegate and event as shown below.
public class EventHolderCallingClass
{
public delegate void HandleExceptionEventDelegate(Exception exception);
public event HandleExceptionEventDelegate HandleExceptionEvent ;
void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
//some operation which caused exception.
}
catch(Exception exception)
{
if(HandleExceptionEvent!=null)
HandleExceptionEvent(exception)
}
}
}
Event Handler Class (Exception Handler):
public EventHandlerClassConstructor()
{
EventHolderCallingClass.HandleExceptionEvent += new EventHolderCallingClass.HandleExceptionEventDelegate(HandleExceptionEventHandler);
}
void HandleExceptionEventHandler(Exception exception)
{
//handle exception here.
}
From my humble test under windows 10 framework 4.6, the thread used by the SystemTimers.Timer elapsed event will not propagate the unhandled exception.
I needed to fire a event to the main thread to notify the unhandled exception happened.
I have a dialog that has to process large quantaties of data (the procedure is quite time consuming - first the ODBC fill takes its time, then the data processing kicks in) and the result is that the Form becomes unresponsive. This is not a problem really, it is enough to just open a "loading screen" in a new thread to notify the user of the process.
Recently I have discovered, that sometimes (it appears to be random) the new thread will throw an unhandled ThreadAbortException causing a crash report dialog box to show up (or JIT).
I do not understand why this exception would be thrown, or why it would be unhandled. Has anyone dealt with this before, or can anyone point me towards the probable cause of this behaviour?
Thank you!
EDIT: In case it matters, I open the loading screen like this:
//start of work load
Thread th = new Thread(new ThreadStart(MakeStep));
th.Start();
...
//end of work or error occurance:
th.Abort();
//
You're calling th.Abort() which injects a ThreadAbortException on the thread th. If that thread doesn't handle the exception it will be reported as an unhandled exception.
It is generally not recommended to abort other threads in this way, as you have no idea if the thread will handle an abort gracefully. A better solution is to use signaling between your threads.
ThreadAbortExceptions are raised when you call Thread.Abort(). Looks like you or a lib you are using is trying to kill your Thread.
If you don't know why it's aborting, better to let it go than to swallow the exception.
That being said, you need to wrap your MakeStep method in a try/catch and log the exception (and, of course, any innter exceptions). Something like this...
public void MakeStep()
{
try
{
InnerMakeStep(); // may throw TAE or some other exception
}catch(Exception e)
{
// log here k
throw; // in case it isn't a TAE
}
}
With the exception logged, the issue can be debugged. Right now, it could be a thousand things.