I thought this approach would be safe, in that it wouldn't allow exceptions to propagate. A colleague of mine suggested that the exceptions may need to be observed on the main thread, and should thus be passed up to the main thread. Is that the answer? Can you see how an exception could leak through this?
private static void InvokeProcessHandlers<T>(List<T> processHandlers, Action<T> action)
{
// Loop through process handlers asynchronously, giving them each their own chance to do their thing.
Task.Factory.StartNew(() =>
{
foreach (T handler in processHandlers)
{
try
{
action.Invoke(handler);
}
catch (Exception ex)
{
try
{
EventLog.WriteEntry(ResourceCommon.LogSource,
String.Format(CultureInfo.CurrentCulture, "An error occurred in a pre- or post-process interception handler: {0}", ex.ToString()),
EventLogEntryType.Error);
}
catch (Exception)
{
// Eat it. Nothing else we can do. Something is seriously broken.
}
continue; // Don't let one handler failure stop the rest from processing.
}
}
});
}
By the way, a stack trace is indeed showing that an exception is leaking from this method.
The exception is AccessViolation, and I believe it has to do with the code that calls this method:
InvokeProcessHandlers<IInterceptionPostProcessHandler>(InterceptionPostProcessHandlers, handler => handler.Process(methodCallMessage, methodReturnMessage));
The getter for InterceptionPostProcessHandlers contains this:
_interceptionPreprocessHandlers = ReflectionUtility.GetObjectsForAnInterface<IInterceptionPreprocessHandler>(Assembly.GetExecutingAssembly());
Just make sure to check parameter for null references before you iterate
other than that there is nothing wrong as log writing is not something to stop the execution, but i would recommend to make it more clean and maintainable by encapsulating the logging into a mothod like:
bool Logger.TryLog(params);
and inside this method do the try with a catch that returns false and if you want to handle it in client code do it and if you dont never mind just call the logger in a clean encapsulated way
A colleague of mine suggested that the exceptions may need to be
observed on the main thread, and should thus be passed up to the main
thread.
How can it be "passed up to the main thread"? The main thread is away and doing its own thing.
The best you can do is to make it configurable and accept an ExceptionHandler delegate that is called.
Related
I have an application performing some additional jobs like cleaning old logs, sending notifications and so on. If one job fails I don't want the whole application to stop working and not perform jobs what left.
So for example,
await SendUsersBirthdayEmailsAsync(); // <-- if something fails while trying to send birthday emails here, I don't want the app to stop working and not clean logs and so on...
await DeleteOutdatedLogsAsync();
await SendSystemNotificationsAsync();
What would you recommend me to go with?
Use try-catch block on every part of the code that can fail.
Depending on what you need, use try-catch-finally block.
On every catch block, log the exception however you want. I use Nlog for logging so i suggest looking into that.
try{
//do work here
}
catch(Exception e){
//log exception here
}
//optional
finally{
//do optional needed work here
}
Something like this:
public bool SendUsersBirthdayEmailsAsync(){
try{
SendMail();
}
catch(Exception e){
LogException(e);
}
//optional
finally{
OptionalWork();
}
}
EDIT: About avoiding using generic exception
You can always use multiple catch blocks any define different behavior for each type of exception. This is useful when you know what kind of exception can be expected.
Example:
public bool SendUsersBirthdayEmailsAsync(){
try{
SendMail();
}
catch (ThreadAbortException tae)
{
LogException(tae);
//do something specific
}
catch (ThreadInterruptedException tie)
{
LogException(tie);
//do something specific
}
catch(Exception e){
LogException(e);
}
//optional
finally{
OptionalWork();
}
}
EDIT 2: Official Microsoft guidance for exception handling.
Use try/catch blocks around code that can potentially generate an exception and your code can recover from that exception. In catch blocks, always order exceptions from the most derived to the least derived. All exceptions derive from Exception. More derived exceptions are not handled by a catch clause that is preceded by a catch clause for a base exception class. When your code cannot recover from an exception, don't catch that exception. Enable methods further up the call stack to recover if possible.
Clean up resources allocated with either using statements, or finally blocks. Prefer using statements to automatically clean up resources when exceptions are thrown. Use finally blocks to clean up resources that don't implement IDisposable. Code in a finally clause is almost always executed even when exceptions are thrown.
Task<Task> task = (SendUsersBirthdayEmailsAsync()
.ContinueWith(x => Task.WhenAll(DeleteOutdatedLogsAsync(), SendSystemNotificationsAsync())));
await await task;
For more general sample the below code provided:
class TaskTest
{
public async void Start()
{
await (
(await One().ContinueWith(x => Task.WhenAll(Two(), Three())))
.ContinueWith(x=> Four()));
}
private async Task One()
{
await Task.Delay(5000);
Console.WriteLine("1");
throw new Exception();
}
private async Task Two()
{
await Task.Delay(2000);
Console.WriteLine("2");
throw new Exception();
}
private async Task Three()
{
await Task.Delay(3000);
Console.WriteLine("3");
throw new Exception();
}
private async Task Four()
{
await Task.Delay(1000);
Console.WriteLine("4");
throw new Exception();
}
}
running this code shows that throwing exceptions inside tasks does not halt the whole program.
If you are already doing it with a scheduler why not separate it into smaller tasks? In that way if one action fails it will not bring down all the others. Also it is a good practice to have many smaller applications with dedicated responsibilities rather than a generic one that does everything.
If you are looking for a reliable option to ensure the process is completed and is traceable, you can go with Hangfire. You can put your retry logic in case of failures by handling exceptions also.
Since the name of the methods suggests, that these methods are independent of each other, just make sure each returns an await-able task and put them into a list. Your use of await suggests, they already do.
Put one try-catch around it and catch the AggregateExeption.
List<Task> tasks = new List<Task>();
try
{
tasks.Add(SendUsersBirthdayEmailsAsync());
tasks.Add(DeleteOutdatedLogsAsync());
tasks.Add(SendSystemNotificationsAsync());
Task.WhenAll(tasks); // waits for all tasks to finish
}
catch (Exception e)
{
//Log e.ToString(); will give you all inner exceptions of the aggregate exception as well, incl. StackTraces, so expect possibly a lot of chars, wherever you log it.
}
This may also speed things up, because they are now running in parallel. But since they all seem to work on a database (most likely the same), it might not be much, if at all, because of the scheduling overhead.
You can implement your methods using the Try-Pattern and have them return Boolean.
Let every method handle exceptions on it's own so that you are sure no unhandled exceptions can be thrown to kill off your application.
In case a failure will result in unrecoverable program state, the methods should return false and your application should quit in a clean way by itself.
Unobserved Task Exceptions
await SendUsersBirthdayEmailsAsync(); // uses TaskScheduler
Since you are working with a TaskScheduler, check out TaskScheduler.UnobservedTaskException.
Occurs when a faulted task's unobserved exception is about to trigger
exception escalation policy, which, by default, would terminate the
process.
You need to use Try-Catch in every function as follow.
try{
//write your code
}
catch(Exception e){
//your exception will be here
}
You can generate a log file for that exception.
Just Do one thing for your log File. Create A Log Class and a log file generate function.
call that function in catch area of your all functions.
Let you create a Log class with name clsLog. and a static function with name InsertLog(string exception, string functionname).
Use this log method in your all function as follow.
public void insertcity()
{
try
{
//Insert city programming
}
catch (exception ex)
{
clsLog.InsertLog(ex.Message,"insertCity");
//do something else you want.
}
}
Hope it will help.
i think if u use
try{
//your nice work
}
catch(Exception e){
//hmm.. error ok i will show u
}
//optional
finally{
//again start the operation if u failed here.
}
i also make the same application in which when some error comes and failed then in the catch exception i make the log in system and also again restart the application in the finally. so it will never die.
I would recommend to found out what exception you getting from async to actually get this exception and understand it you can use on a main Thread:
MyTask().GetAwaiter().GetResult();
This will allow you to see the text of the actual exception that you have on your await Thread.
And a little bit if you don't want a main Thread to return to the line with await you also can use:
await SendUsersBirthdayEmailsAsync().ConfigureAwait(false);
This will just continue your Task on the nearest free Thread.
But need to say this will cause an exception on Android because it have some restrictions of using Threads.
In the case you don't want to waste your time or don't need to handle the exception manually and fixing it try, catch finally is always an option.
The answer that Andreas used - fits what I was thinking - however I would make one more piece - A Cancellation Token - with a time limit on how long you would think is enough time - so that everything completes.
The individual tasks in the Wait means that they all come back together at that point while they execute seperately. You can catch the agreggate exceptions if they occur - and then determine if it was timeout - or something you need to log.
The Two suggestions on UnhandledException and UnhandledTask Exception SHOULD be included also - for what ever reason that they stop..
I would also think about making this a Windows service so that you can pass the cancellation token into the tasks from startup - and have a timer on when the service actually runs - instead of a scheduled task - then with all the exception handling you can see what the log tells you over time - which feels a little more resilient than a console app to me - but that is how we normally run tasks in this vein.
You can start and stop a service like this in a console app for testing - and then hand it off into a project that handles the OnStart and OnStop events - passing the Cancellation token in - OnStop would cancel the token and stop the service loops.
I'm trying to handle errors that are passed through 2 dlls I've created. So Console.exe calls dll 1. dll 1 completes an async MQ message read and the handler calls dll 2. If dll 2 errors it passes the Exception (throw) without a problem. But the dll 1 (async) handler catch the throw from dll 2 and give me an unhandled by user message.. I have followed the msdn code to add in the IAsyncResult to keep the hander alive but the issue persists.
can anyone advise on how I should handle this stack and get the handler error returned to the console.exe program so I can present it to the user. Code below:-
Console.exe (snippet)
try
{
_msmq.MSMQ_GetMessage(_msgPath);
//set up the print of the number of queue messages
Console.WriteLine("Main thread: starting a timer");
Timer t = new Timer(ComputeBoundOp, _msgPath, 0, 2000);
Console.Write("Press any key to continue . . .");
Console.ReadKey(true);
t.Dispose(); // Cancel the timer now
}
catch (MessageQueueException _msgQex)
{
Console.WriteLine("An error occurred with the queue:- " + _msgQex);
}
catch (Exception _ex)
{
Console.WriteLine("An error occurred with the queue:- " + _ex);
}
dll 1
public void MSMQ_GetMessage(string _MQ_Path)
{
try
{
//set the correct message queue
MessageQueue _msgQ = new MessageQueue(_MQ_Path, QueueAccessMode.ReceiveAndAdmin);
//set the format of the message queue
_msgQ.Formatter = new XmlMessageFormatter(new Type[] { typeof(_TwitterStreamFeed) });
_msgQ.ReceiveCompleted += new ReceiveCompletedEventHandler(_msgQ_RecieveCompleted);
IAsyncResult _result = _msgQ.BeginReceive();
_asyncList.Add(_result); // asyncList is a global variable of type System.Collections - > this allows the callback to remain open and therefore nit garbage collected while the async thread runs off on it's own
}
catch (Exception _ex)
{
throw new Exception("_msgQ_get Message threw the following error :- " + _ex);
}
}
//method to process message
public void _msgQ_RecieveCompleted(object sender, ReceiveCompletedEventArgs e)
{
try
{
//queue that have received a message
MessageQueue _mq = (MessageQueue)sender;
//get the messge off the queue
Message _mqmsg = _mq.EndReceive(e.AsyncResult);
//set the values back into a formatted struct
//now process your SQL....
Azure_SQL _azuresql = new Azure_SQL();
_azuresql.writeMessageToStorage((_TwitterStreamFeed)_mqmsg.Body);
//refresh queue just in case any changes occurred (optional)
_mq.Refresh();
//tell MessageQueue to receive next message when it arrives
_mq.BeginReceive();
}
catch (Exception _ex)
{
throw;
}
dll 2
public void writeMessageToStorage(_TwitterStreamFeed _msmq_message_as_TSF)
{
try
{
// now do something with the class - i..e write the values to the database
SqlConnection _azurecon = new SqlConnection(_AzuzeSQLConnection);
SqlCommand _sqlcmd = new SqlCommand();
//Setup the command string to call the stored procedure
//Add the parameter to the parameters collection of the command
blah blah blah......... Do SQL writing to Db
_azurecon.Open();
SqlDataReader _sqldr_tweet_place = _sqlcmd_place.ExecuteReader(CommandBehavior.CloseConnection);
}
//now close things off
_azurecon.Close();
}
catch (Exception _ex)
{
// Throw the error to preserve the original
throw;
}
The reason for this is that, internally, the MessageQueue class is explicitly swallowing the exception. Where the MessageQueue class raises the ReceiveCompleted event, it's inside of a try-catch statement - and the catch block is empty. Suffice it to say, if an exception occurs inside your ReceiveCompleted event handler, _msgQ_RecieveCompleted(), nothing's ever going to know it happened.
I see a couple of options, in order of preference.
Option 1 - Shift where the asynchronous call is made
Since this exception-swallowing behavior only occurs when using BeginReceive(), in MSMQ_GetMessage(), you can switch from using BeginReceive() to just Receive(). Then, make your call to MSMQ_GetMessage() asynchronous and any exception that gets thrown will be propagated as expected.
As a side note, a new(er) alternative for making asynchronous calls is available; the Task<> class. As opposed to the Thread class, Task<> has exception handling functionality built in. It does, however, require Framework 4 or higher. There is a good explanation of it's use described in the answer here.
Option 2 - Use a custom event
If refactoring the asynchronous call isn't an option, you can create a custom event in your class in 'dll 2' and subscribe to that event in 'Console.exe'. So when an exception occurs in _msgQ_RecieveCompleted(), you can raise the event and 'Console.exe' will be notified.
The MessageQueue.BeginReceive() method uses the standard .NET APM (Asynchronous Programming Model) pattern. It is very important to understand how it works to know how to properly deal with exceptions. Be sure to read the MSDN article, there are lots of other googable resources available.
In APM, the callback that tells you that a message was received in executed on a thread-pool thread. Which is a very efficient way to get code to run quickly. It is however also a very troublesome way when something goes wrong. The EndReceive() method call is likely to throw an exception, it does so to tell you that the receive operation could not be completed. A standard exception it will throw is ObjectDisposedException. Which will happen when the MessageQueue object gets disposed. In your case when your program terminates. You need to catch that exception and exit from your event handler, it is an expected exception and signals that nothing more useful is going to happen next since the queue was closed.
Then there's a raft of possible exceptions that can be raised by major mishaps in the message queue plumbing. Plus whatever you do with the message. Looks like you execute some Azure code, plenty of ways that can fall over. If you let such an exception escape from the callback method, like you do, then there's no catch clause anywhere in the call stack that is going to handle the exception. The standard way .NET deals with unhandled exceptions is to raise the AppDomain.UnhandledException event and terminate your program. If you didn't actually implement that event then there's nothing decent to look at to diagnose the reason your program ended, the Windows Error Reporting dialog has no good diagnostic.
Whether or not you should try to handle the exception and prevent the program from terminating is up to you. But it pretty strongly fits the "don't shoot the messenger" pattern, it is very unlikely your program can meaningfully continue to execute when such an exception is raised. It invariably takes a human to fix the problem, like restoring the network connection or fixing the message queue. If you do catch it then the odds that the same exception is raised over and over again is fairly likely. After all, there wasn't anything decent you could do in your code to repair the network.
So the best guidance here is to not try, just make sure that IT staff has a good diagnostic so they can repair the problem. Do implement the AppDomain.UnhandledException and display and log the e.UnhandledException.ToString() value. This will also let you learn the number of ways that your program can fail. There might be some conditions that are common enough to warrant catching, something like a temporary network outage. At that point you'll also know what to do about it, in other words what kind of code to write in the catch clause. There is no possible way you know what to write right now, you should therefore not try.
Last but not least, do note that you got yourself into this pickle because you used BeginReceive() unnecessarily. You've already got a perfectly good thread to do work on. But it doesn't do anything useful, it is stuck in the Console.ReadKey() method. Particularly in .NET 4.5 a very tricky method to call, it prevents other threads from writing anything to the console. So your error reporting won't work, it will deadlock when it tries to use Console.WriteLine() to write a diagnostic.
You might as well use MessageQueue.Read() instead. Now dealing with exceptions is a lot easier since they occur on the same thread. The MessageQueue.SynchronizingObject can also be helpful to get completion callbacks to occur on the main thread, but that only works in a GUI app, not in a console app.
I'm refactoring a medium-sized WinForms application written by other developers and almost every method of every class is surrounded by a try-catch block. 99% of the time these catch blocks only log exceptions or cleanup resources and return error status.
I think it is obvious that this application lacks proper exception-handling mechanism and I'm planning to remove most try-catch blocks.
Is there any downside of doing so? How would you do this? I'm planning to:
To log exceptions appropriately and prevent them from propagating to the user, have an Application.ThreadException handler
For cases where there's a resource that needs cleanup, leave the try-catch block as it is
Update: Using using or try-finally blocks is a better way. Thanks for the responses.
In methods that "return-false-on-error", let the exception propagate and catch it in the caller instead
Any corrections/suggestions are welcome.
Edit: In the 3rd item, with "return-false-on-error" I meant methods like this:
bool MethodThatDoesSomething() {
try {
DoSomething(); // might throw IOException
} catch(Exception e) {
return false;
}
}
I'd like to rewrite this as:
void MethodThatDoesSomething() {
DoSomething(); // might throw IOException
}
// try-catch in the caller instead of checking MethodThatDoesSomething's return value
try {
MethodThatDoesSomething()
} catch(IOException e) {
HandleException(e);
}
"To log exceptions appropriately and prevent them from propagating to the user, have an Application.ThreadException handler"
Would you then be able to tell the user what happened? Would all exceptions end up there?
"For cases where there's a resource that needs cleanup, leave the try-catch block as it is"
You can use try-finally blocks as well if you wish to let the exception be handled elsewhere. Also consider using the using keyword on IDisposable resources.
"In methods that "return-false-on-error", let the exception propagate and catch it in the caller instead"
It depends on the method. Exceptions should occur only in exceptional situations. A FileNotFoundException is just weird for the FileExists() method to throw, but perfectly legal to be thrown by OpenFile().
For cleanup rather use try-finally or implement the IDisposable as suggested by Amittai. For methods that return bool on error rather try and return false if the condition is not met. Example.
bool ReturnFalseExample() {
try {
if (1 == 2) thow new InvalidArgumentException("1");
}catch(Exception e) {
//Log exception
return false;
}
Rather change to this.
bool ReturnFalseExample() {
if (1 == 2) {
//Log 1 != 2
return false;
}
If i'm not mistaken try catches are an expensive process and when possible you should try determine if condition is not met rather then just catching exceptions.
}
As an option for "return-false-on-error" you can clean up the code this way:
static class ErrorsHelper {
public static bool ErrorToBool(Action action) {
try {
action();
return true;
} catch (Exception ex) {
LogException(ex);
return false;
}
}
private static void LogException(Exception ex) {
throw new NotImplementedException();
}
}
and usage example:
static void Main(string[] args) {
if (!ErrorToBool(Method)) {
Console.WriteLine("failed");
} else if (!ErrorToBool(() => Method2(2))) {
Console.WriteLine("failed");
}
}
static void Method() {}
static void Method2(int agr) {}
The best is as said by others, do exception handling at 1 place. Its bad practice to conceal the raised exception rather than allowing to bubble up.
You should only handle only the exceptions that you are expecting, know how to handle and they are not corrupt the state of your application, otherwise let them throw.
A good approach to follow is to log the exception first, then Restart your application, just like what Microsoft did when office or visual studio crashing. To do so you have to handle the application domain unhanded exception, so:
AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;
//Add these two lines if you are using winforms
Application.ThreadException += OnApplicationThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
private void OnCurrentDomainUnhandledException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
//Log error
//RestartTheApplication
}
Here an example on how to restart your application.
I think your strategy of removing try/catch block which just appear to do generic thoughtless logging is fine. Obviously leaving the cleanup code is necessary. However, I think more clarification is needed for your third point.
Return false on error methods are usually OK for things where exceptions are unavoidable, like a file operation in your example. Whereas I can see the benefit of removing exception handling code where it's just been put in thoughtlessly, I would consider carefully what benefit you get by pushing responsibility for handling an exception of this kind higher up in the call chain.
If the method is doing something very specific (it's not generic framework code), and you know which callers are using it, then I'd let it swallow the exception, leaving the callers free of exception handling duties. However, if it's something more generic and maybe more of a framework method, where you're not sure what code will be calling the method, I'd maybe let the exception propagate.
You may try to use AOP.
In AOP through PostSharp, for example, you can handle exceptions in one central place (piece of code) as an aspect.
Look at the examples in documentation to have an idea => Docs on Exception Handling with PostSharp.
we can remove try and catch by adding condition Like
string emailAddresses = #"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$";
if (!Regex.IsMatch(Email, emailAddresses))
{
throw new UserFriendlyException($"E-mail Address Is not Valid");
}**strong text**
I am using the following event to catch unhandled exceptions in the main UI thread.
Application.ThreadException
Unfortunately, it does not catch those unhandled errors in seperate threads. I am aware of
AppDomain.CurrentDomain.UnhandledException
However, this seems to shut down the application upon triggering, where as the former does not.
Is there a way to deal with unhandled exceptions on separate threads, without the application closing?
#Ani have already answered your question. Although I don't agree that unhandled exceptions in threads should terminate applications. Using threads usually means that you have some kind of server application. Bringing it down could result in a lot of angry users.
I've written a small piece about proper exception handling: https://coderr.io/exception-handling
You should always catch exceptions for threads. I usually use the following pattern:
void ThreadMethod(object state)
{
try
{
ActualWorkerMethod();
}
catch (Exception err)
{
_logger.Error("Unhandled exception in thread.", err);
}
}
void ActualWorkerMethod()
{
// do something clever
}
It's a whole lot easier to find thread methods that doesn't handle exceptions properly by moving the logic into a seperate method and just keep the try/catch block in the thread method.
Of course you should always handle all exceptions. But if you are currently incapable of doing so, you can try the following:
The application will crash/close after the UnhandledException event handler.
You can just add a delay in the event handler to prevents this. Other threads with no exception (e.g. the main thread) can continue. So the application will not close and can continue. However, the thread with the exception will remain in sleep. And therefor you may get a "memory/thread leak".
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// Log the exception, display it, etc
Debug.WriteLine((e.ExceptionObject as Exception).Message);
Thread.Sleep(100000000);
}
At this moment there is not a better solution.
You may find to change the config file, but i think that is just as dirty: https://stackoverflow.com/a/15348736
Yes, you have to manually catch exceptions on threads.
However, this code:
void ThreadMethod(object state)
{
try
{
ActualWorkerMethod();
}
catch (Exception err)
{
_logger.Error("Unhandled exception in thread.", err);
}
}
void ActualWorkerMethod()
{
// do something clever
}
can be simplified to this using PostSharp:
[LogExceptions]
void ActualWorkerMethod()
{
// do something clever
}
The code that I want to write is like this:
void MethodOnThreadA()
{
for (;;)
{
// Do stuff
if (ErrorConditionMet)
ThrowOnThread(threadB, new MyException(...));
}
}
void MethodOnThreadB()
{
try
{
for (;;)
{
// Do stuff
}
}
catch (MyException ex)
{
// Do the right thing for this exception.
}
}
I know I can have thread B periodically check, in thread safe way, to see if a flag has been set by thread A, but that makes the code more complicated. Is there a better mechanism that I can use?
Here is a more fleshed out example of periodically checking:
Dictionary<Thread, Exception> exceptionDictionary = new Dictionary<Thread, Exception>();
void ThrowOnThread(Thread thread, Exception ex)
{
// the exception passed in is going to be handed off to another thread,
// so it needs to be thread safe.
lock (exceptionDictionary)
{
exceptionDictionary[thread] = ex;
}
}
void ExceptionCheck()
{
lock (exceptionDictionary)
{
Exception ex;
if (exceptionDictionary.TryGetValue(Thread.CurrentThread, out ex))
throw ex;
}
}
void MethodOnThreadA()
{
for (;;)
{
// Do stuff
if (ErrorConditionMet)
ThrowOnThread(threadB, new MyException(...));
}
}
void MethodOnThreadB()
{
try
{
for (;;)
{
// Do stuff
ExceptionCheck();
}
}
catch (MyException ex)
{
// Do the right thing for this exception.
}
}
This is NOT a good idea
This article talks about ruby's timeout library. which throws exceptions across threads.
It explains how doing such a thing is fundamentally broken. It's not just broken in ruby, it's broken anywhere that throws exceptions across threads.
In a nutshell, what can (and does) happen is this:
ThreadA:
At some random time, throw an exception on thread B:
ThreadB:
try {
//do stuff
} finally {
CloseResourceOne();
// ThreadA's exception gets thrown NOW, in the middle
// of our finally block and resource two NEVER gets closed.
// Obviously this is BAD, and the only way to stop is to NOT throw
// exceptions across threads
CloseResourceTwo();
}
Your 'periodic checking' example is fine, as you're not actually throwing exceptions across threads.
You're just setting a flag which says "throw an exception the next time you look at this flag", which is fine as it doesn't suffer from the "can be thrown in the middle of your catch or finally block" problem.
However, if you're going to do that, you may as well just be setting an "exitnow" flag, and using that and save yourself the hassle of creating the exception object. A volatile bool will work just fine for that.
There are enough problems with exceptions that can be thrown on threads by other mechanisms, like aborting threads and the likes, that you should find another way of doing it.
An exception is a mechanism used to signal that a process has experienced something exceptional that it cannot deal with. You should try to avoid writing the code so that an exception is used to signal that something else has experienced something exceptional.
That other thread will most likely not know how to handle the exception in all cases where it could be thrown by your code.
In short, you should find some other mechanism for aborting your threads than using exceptions.
Use event objects or similar to tell a thread to abort its processing, that's the best way.
What Orion Edwards is saying is not entirely true: is not the "only" way.
// Obviously this is BAD, and the only way to stop is to NOT throw
// exceptions across threads
Using CER (Constrained Execution Regions) in C# allows you to release your resources as an atomic operation, protecting your code from inter-thread exceptions. This technique is used by several classes of the .NET Framework which work with Windows' native API, where an unreleased handle may cause a memory leak.
See http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx
The following example shows how to reliably set handles by using the PrepareConstrainedRegions method. To reliably set a handle to a specified pre-existing handle, you must ensure that the allocation of the native handle and the subsequent recording of that handle within a SafeHandle object is atomic. Any failure between these operations (such as a thread abort or out-of-memory exception) will result in the native handle being leaked. You can use the PrepareConstrainedRegions method to make sure that the handle is not leaked.
As simple as:
public MySafeHandle AllocateHandle()
{
// Allocate SafeHandle first to avoid failure later.
MySafeHandle sh = new MySafeHandle();
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally // this finally block is atomic an uninterruptible by inter-thread exceptions
{
MyStruct myStruct = new MyStruct();
NativeAllocateHandle(ref myStruct);
sh.SetHandle(myStruct.m_outputHandle);
}
return sh;
}
While researching another issue, I came across this article which reminded me of your question:
Plumbing the Depths of the ThreadAbortException using Rotor
It shows the gyrations that .NET goes through to implement Thread.Abort() -- presumably any other cross-thread exception would have to be similar. (Yeech!)
I'm interested to know why you would want to do this. There's not an easy way to do it, because it's not a good practice. You should probably go back to your design and figure out a cleaner way to accomplish the end goal.
I don't think that's a good idea..
Take another crack at this problem - Try using some other mechanism like shared data to signal between threads.
Like the others, I'm not sure that's such a good idea, but if you really want to do it, then you can create a subclass of SynchronizationContext that allows posting and sending delegates to the target thread (if it's a WinForms thread the work is done for you as such a subclass already exists). The target thread will have to implement some sort of a message pump equivalent though, to receive the delegates.
#Orion Edwards
I take your point about an exception being thrown in the finally block.
However, I think there is a way - using yet another thread - of using this exception-as-interrupt idea.
Thread A:
At some random time, throw an exception on thread C:
Thread B:
try {
Signal thread C that exceptions may be thrown
//do stuff, without needing to check exit conditions
Signal thread C that exceptions may no longer be thrown
}
catch {
// exception/interrupt occurred handle...
}
finally {
// ...and clean up
CloseResourceOne();
CloseResourceTwo();
}
Thread C:
while(thread-B-wants-exceptions) {
try {
Thread.Sleep(1)
}
catch {
// exception was thrown...
if Thread B still wants to handle exceptions
throw-in-B
}
}
Or is that just silly?