What is the recommended way to protect against resource leaks in the context of ThreadAbortException?

I am working on improving exception security for a piece of code, and I realized that an increased ThreadAbortException can lead to unwanted resource leaks even when protecting resources using the C # using construct. For example, consider the following code (which can be executed in a separate thread).

 using (TextWriter writer = CreateWriter(filename)) { // do something with the writer. } TextWriter CreateWriter(string filename) { return new CustomWriter(File.OpenWrite(filename)); } 

If the thread executing this code abnormally terminates, then I want the file descriptor referenced by filename to be closed immediately. Can I do this without replacing the using construct with a try / finally block?

My guess is that a ThreadAbortException can be thrown at any time, which means that I have to pay attention to what happens between the statements. Although I can defend against an exception in CreateWriter using a try / finally block, the using construct will not do the same until the expression in parentheses is evaluated, which means that the file resource remains open if an exception occurs immediately after returning CreateWriter .

I understand that the finalizer will eventually release the file descriptor, but I wonder if there is a deterministic way to solve this problem without catching a ThreadAbortException in every place where CreateWriter used.

+4
source share
4 answers

There is a compromise.

  • Be sure to immediately close all resources even if there is a ThreadAbortException
  • Simple code but temporarily leaking resources if Abort () is called

I assume you are not calling Abort, and just want you to be safe if someone else is. If you call Abort, I would advise you not to. This is not the only problem you will encounter. There are other problems with Abort in the documentation .

# 2 is a valid choice because calling Abort () functions should expect this.

If you want to choose # 1, then I don’t think that even a simple try / catch will help. If a ThreadAbortException can occur everywhere, it can happen after opening the file (inside File.OpenWrite ()), and before you can assign it to a variable that you can call Dispose (), you will have the same problem as using it in your code.

You need semantics like

  using (var handle = GetUnOpenedHandle()) { handle.Open(); // this can't involve assignment to any field of handle } 

I am not sure if this is possible.

+1
source

Yes, a deterministic way to prevent this is to use Thread.Abort . Ever. A signal to your flows, which is the time to stop, and let them cease grace. Thread.Abort is a large large red herring placed in the API just to touch you.;)

http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation

+4
source

In many cases (but definitely not all), you can protect against ThreadAbortException . Most of the critical code in .NET BCL does this pretty well already. The problem is that it is really complicated. And for this reason, most people recommend, and rightly so, to avoid interrupting threads. Starting with version 2.0, the CLR made the flow more intermittent and introduced a new set of APIs to help code developers protect them. Take a look at Limited Runtime Areas for an in-depth look at how this all works.

I believe that you relate correctly to your problems with an example using block. For regions with limited execution to work correctly, out-of-band (asynchronous) exceptions must occur from within the try block. But due to the using extension, the expression is evaluated outside the try block. Contrast this with the extension of the lock block, which evaluates the expression from the try block. Well, this is true with version 4.0 of the framework anyway, and it has been specifically modified to protect against these exceptions.

So, the question is why the same change was not made with the using block. According to Joe Duffy , this was an acceptable omission, since the assumption is that the interruption of the stream should always be accompanied by the termination of the application, which should in any case.

So yes. Your code does not tolerate out-of-band (asynchronous) exceptions. But the prevailing wisdom from the smart than me is that it should not be.

+1
source

Cancellation of interrupts is most often used in case of a fatal error, so your answer should probably be that your application terminates. If you are trying to completely clear your threads, use Thread.Join ().

0
source

All Articles