Click here to Skip to main content
11,427,997 members (59,526 online)
Click here to Skip to main content

Using Keyword Is Not Abort Safe

, 6 Mar 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
This article shows why not even the "using" keyword is a failsafe mechanism


C# is a safe and managed language. By safe, we can understand it will help developers avoid common errors, like causing memory leaks or accessing invalid memory. In fact, .NET is really good at this, but the Garbage Collection does not occur immediately so, when we need to free a resource immediately, we must call some type of "free" method, like Close in files and database connections, Commit or Rollback transactions or, in general, the Dispose() method, which is also implemented by files, database objects and transactions.

Dispose() methods free the associated resources immediately, so a file being written can now be read by another process, a database connection can return to the pool and other unmanaged resources (like windows Handles) are freed immediately, releasing memory.

But, how do we call Dispose()?

In C#, we have the using keyword which must be used as follows:

using(var disposable = new DisposableType())
  ... do what's needed with the disposable variable here ...

And, at the end of the block, the Dispose will be called. Such code will be compiled like:

  var disposable = new DisposableType();
    ... do what's needed with the disposable variable here ...
    if (disposable != null)

Even the new keyword will never return null, the "pattern" includes the if (disposable != null), but I really think the JIT will optimize and remove such unnecessary if.

So, this code is safe, right? Any exception after the disposable object is created will be protected by the finally clause and will call Dispose.

Well, no. For synchronous exceptions, that's correct, but there are asynchronous exceptions too, in special ThreadAbortException.

Imagine that just after setting the disposable value and before the try, a ThreadAbortException is thrown, by a request to Abort from another thread. We are not yet in the try, so the finally will not be called. This is an issue. It will not cause a memory leak, considering that GC will eventually collect the object, but such resource will be held for a long time. If this is a database connection, it could not return to the pool. If this is a file, it can be kept in exclusive mode forbidding anyone else from using it.

So, how do we solve this? I will present the solution later, but I will first show something that looks like a solution. Why? Because I think that not knowing the problem with this pseudo solution will make someone try to use it, specially because there are some places that already use this structure as the "right" one.

The Code

DisposableType disposable = null;
  disposable = new DisposableType();
  ... use the disposable object here ...
  if (disposable != null)

In this solution, the disposable is initialized with null. So, the block is protected with a try/finally before the disposable object is created. If the ThreadAbortException comes before object is created, the if in the finally will make it work. If the ThreadAbortException comes just after the object is created, it will work also. But, there is still a problem.

Abort can happen at any assembly instruction. Even our line looks like disposable = new DisposableType(), in assembler we first allocate the type and then we store such result in disposable variable. To make it worse, constructors can also be interrupted in the middle (I made many tests myself, even not having examples to show exactly where the exceptions happen).

So, is there a possible way to solve the problem? Yes. But we must use it with caution. As already shown, when an exception is thrown the finally block gets executed. If we are already in the finally block, it continues to execute normally, so an Abort called for a thread that is already in finally block does not force it to exit to another finally block, missing some steps. So, we can use this, we put all the code that should not be blocked inside a finally block.

But, remember, use it with caution. If you use any blocking operation in such block, you will not be able to Abort the thread even if you need to. This can be a very frustrating user experience.

So, let's see the code:

DisposableType disposable = null;
    disposable = new DisposableType();

  ... use the disposable object here ...
  if (disposable != null)

With this solution, or the Abort happens before the DisposableType is allocated, or after it is fully allocated and the variable is set. No "in-the-middle" aborts.

So, this is it? Well, for ThreadAbortExceptions, yes. For other asynchronous exceptions, no. If you look at the documentation of CERs (Constrained Execution Regions), be prepared to deal with the ThreadAbortException is only one of the needed cautions. The system can run out-of-memory when it needs to compile a method or the application can be asked to shutdown abruptly, avoiding normal finally clauses. But, don't think this makes such a technique obsolete. ThreadAbortExceptions are much more common than the other exceptions and, specially when the application is shutdown abruptly, files or database connections left open will be reclaimed by the operating system either way.


The technique presented works, but it is ugly. So, I decided to create some classes and helper methods. The most important one is in the AbortSafe class, and is the Run method that receives 3 parameters. Let's look at the method:

public static void Run(Action allocationBlock, Action codeBlock, Action finallyBlock)
	if (allocationBlock == null)
		throw new ArgumentNullException("allocationBlock");
	if (codeBlock == null)
		throw new ArgumentNullException("codeBlock");
	if (finallyBlock == null)
		throw new ArgumentNullException("finallyBlock");


It simply receives three actions. If the allocation starts, it is guaranteed to finish, even if the abort happens in the middle. Independent from the success of allocation, finalization will be run. The only block that is abortable is the code block.

Let's look a simple example of how to use it:

DisposableType disposable = null;
  () => disposable = new DisposableType(),
  () =>
    ... do what you need with the disposable object...
  () => disposable.CheckedDispose()

The CheckedDispose is an extension method found in Pfz.Extensions.DisposeExtensions namespace. It will simply check if the variable is not null before disposing it. I did this only to avoid creating a new code block to do the "if". As you can see, the code is "less" ugly than creating an empty try to program in the finally block. Also, it does not look like an error, so it does not have the same chance of being "corrected" by someone else that does not understand why the code was written in a finally clause.


In the attached zip is a program that creates and aborts threads, which will be creating and recreating the same file, but allowing you to choose the way it will do this:

  1. With the using keyword
  2. With the pseudo-solution
  3. With the AbortSafe solution

The 1st and 2nd, at some time, will cause an IO exception because the file is "already opened", while the 3rd will not cause such exception.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Paulo Zemek
Engineer Microsoft Corporation
United States United States
I started to program computers when I was 11 years old, as a hobbist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.

At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do they work easier, faster and with less errors.

Now I just started working as a Senior Software Engineer at Microsoft.

Want more info or simply want to contact me?
Take a look at:
Or e-mail me at:

Codeproject MVP 2012, 2015
Microsoft MVP 2013-2014

Comments and Discussions

QuestionI don't understand the problem described by the first solution Pin
polarboy18-Jan-13 6:10
memberpolarboy18-Jan-13 6:10 
AnswerRe: I don't understand the problem described by the first solution Pin
Paulo Zemek19-Jan-13 7:16
memberPaulo Zemek19-Jan-13 7:16 
GeneralRe: I don't understand the problem described by the first solution Pin
polarboy20-Jan-13 16:35
memberpolarboy20-Jan-13 16:35 
GeneralRe: I don't understand the problem described by the first solution Pin
Paulo Zemek21-Jan-13 6:45
memberPaulo Zemek21-Jan-13 6:45 
GeneralMy vote of 5 Pin
phil.o2-Jan-13 23:28
memberphil.o2-Jan-13 23:28 
GeneralRe: My vote of 5 Pin
Paulo Zemek3-Jan-13 3:36
mvpPaulo Zemek3-Jan-13 3:36 
GeneralOff Topic Pin
OriginalGriff6-Feb-13 7:10
mvpOriginalGriff6-Feb-13 7:10 
GeneralRe: Off Topic Pin
phil.o6-Feb-13 7:17
memberphil.o6-Feb-13 7:17 
GeneralRe: Off Topic Pin
OriginalGriff6-Feb-13 7:31
mvpOriginalGriff6-Feb-13 7:31 
GeneralMy vote of 5 Pin
Ivaylo5ev4-Sep-12 9:27
memberIvaylo5ev4-Sep-12 9:27 
GeneralRe: My vote of 5 Pin
Paulo Zemek3-Jan-13 3:36
mvpPaulo Zemek3-Jan-13 3:36 
GeneralMy vote of 4 Pin
Patrick Kalkman21-Apr-11 6:23
memberPatrick Kalkman21-Apr-11 6:23 
GeneralTwo-step object creation Pin
supercat98-Mar-10 7:02
membersupercat98-Mar-10 7:02 
GeneralRe: Two-step object creation [modified] Pin
Paulo Zemek9-Mar-10 8:21
memberPaulo Zemek9-Mar-10 8:21 
GeneralMy Vote of 3: No Proof Pin
aspdotnetdev5-Dec-09 13:35
memberaspdotnetdev5-Dec-09 13:35 
GeneralRe: My Vote of 3: No Proof Pin
Paulo Zemek7-Dec-09 2:03
memberPaulo Zemek7-Dec-09 2:03 
GeneralRe: My Vote of 3: No Proof Pin
Paulo Zemek7-Dec-09 2:11
memberPaulo Zemek7-Dec-09 2:11 
Look at this program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestApplication
	class Program
		static void Main(string[] args)
			Program value1 = null;
			Program value2 = null;
				value1 = new Program();
				value2 = new Program();

And the generated code:
.method private hidebysig static void  Main(string[] args) cil managed
  // Code size       54 (0x36)
  .maxstack  1
  .locals init ([0] class TestApplication.Program value1,
           [1] class TestApplication.Program value2)
  IL_0000:  nop
  IL_0001:  ldnull
  IL_0002:  stloc.0
  IL_0003:  ldnull
  IL_0004:  stloc.1
    IL_0005:  nop


// this is the allocation.
    IL_0006:  newobj     instance void TestApplication.Program::.ctor()


// this is the assignment. Imagine the abort cames between IL_0006 and IL_000b
    IL_000b:  stloc.0

    IL_000c:  ldloc.0
    IL_000d:  call       void [mscorlib]System.GC::KeepAlive(object)
    IL_0012:  nop
// again, first the allocation.
    IL_0013:  newobj     instance void TestApplication.Program::.ctor()

// and then the assignment.
    IL_0018:  stloc.1

    IL_0019:  ldloc.1
    IL_001a:  call       void [mscorlib]System.GC::KeepAlive(object)
    IL_001f:  nop
    IL_0020:  nop
    IL_0021:  leave.s    IL_0034
  }  // end .try
// this block may not dispose the items, but it shows how the variables are get from the ldloc.0 and ldloc.1, which are stored just AFTER the allocation.

    IL_0023:  nop
    IL_0024:  ldloc.0
    IL_0025:  call       void [mscorlib]System.Console::WriteLine(object)
    IL_002a:  nop
    IL_002b:  ldloc.1
    IL_002c:  call       void [mscorlib]System.Console::WriteLine(object)
    IL_0031:  nop
    IL_0032:  nop
    IL_0033:  endfinally
  }  // end handler
  IL_0034:  nop
  IL_0035:  ret
} // end of method Program::Main

GeneralRe: My Vote of 3: No Proof Pin
aspdotnetdev7-Dec-09 5:55
memberaspdotnetdev7-Dec-09 5:55 
GeneralRe: My Vote of 3: No Proof Pin
aspdotnetdev7-Dec-09 7:51
memberaspdotnetdev7-Dec-09 7:51 
GeneralRe: My Vote of 3: No Proof Pin
aspdotnetdev7-Dec-09 5:58
memberaspdotnetdev7-Dec-09 5:58 
GeneralRe: My Vote of 3: No Proof Pin
Paulo Zemek7-Dec-09 7:41
memberPaulo Zemek7-Dec-09 7:41 
GeneralRe: My Vote of 3: No Proof Pin
aspdotnetdev7-Dec-09 7:49
memberaspdotnetdev7-Dec-09 7:49 
GeneralRe: My Vote of 3: No Proof [modified] Pin
Paulo Zemek7-Dec-09 8:03
memberPaulo Zemek7-Dec-09 8:03 
GeneralRe: My Vote of 3: No Proof Pin
aspdotnetdev7-Dec-09 9:29
memberaspdotnetdev7-Dec-09 9:29 
GeneralRe: My Vote of 3: No Proof [modified] Pin
Paulo Zemek7-Dec-09 10:41
memberPaulo Zemek7-Dec-09 10:41 
Generalnice article but... Pin
urix931-Dec-09 7:10
memberurix931-Dec-09 7:10 
GeneralRe: nice article but... [modified] Pin
Paulo Zemek1-Dec-09 7:29
memberPaulo Zemek1-Dec-09 7:29 
GeneralMy vote of 1 Pin
Dr. Jones DK1-Dec-09 2:52
memberDr. Jones DK1-Dec-09 2:52 
GeneralRe: My vote of 1 Pin
John Kasra25-Dec-09 18:54
memberJohn Kasra25-Dec-09 18:54 
GeneralNice analysis Pin
CurtainDog30-Nov-09 18:31
memberCurtainDog30-Nov-09 18:31 
GeneralRe: Nice analysis Pin
Paulo Zemek1-Dec-09 1:38
memberPaulo Zemek1-Dec-09 1:38 
Generalexcellent job dude Pin
Bishoy Ghaly30-Nov-09 10:11
memberBishoy Ghaly30-Nov-09 10:11 
GeneralRe: excellent job dude Pin
Paulo Zemek30-Nov-09 10:28
memberPaulo Zemek30-Nov-09 10:28 
GeneralOk, I have investigated your source code and made a re-vote, but is the IO exception what you are talking about? [modified] Pin
Miller429-Nov-09 8:00
memberMiller429-Nov-09 8:00 
GeneralRe: Ok, I have investigated your source code and made a re-vote, but is the IO exception what you are talking about? Pin
Paulo Zemek30-Nov-09 2:03
memberPaulo Zemek30-Nov-09 2:03 
GeneralFrom J.Duffy's blog Pin
reflex@codeproject28-Nov-09 9:24
memberreflex@codeproject28-Nov-09 9:24 
GeneralRe: From J.Duffy's blog Pin
Paulo Zemek30-Nov-09 2:01
memberPaulo Zemek30-Nov-09 2:01 
GeneralRe: From J.Duffy's blog Pin
Mikko Puonti9-Mar-10 8:56
memberMikko Puonti9-Mar-10 8:56 
GeneralRe: From J.Duffy's blog Pin
Paulo Zemek9-Mar-10 10:05
memberPaulo Zemek9-Mar-10 10:05 
GeneralRe: From J.Duffy's blog Pin
Paulo Zemek9-Mar-10 11:22
memberPaulo Zemek9-Mar-10 11:22 
GeneralMy vote of 2 [It was my fault, I have voted 5] Pin
Miller428-Nov-09 6:08
memberMiller428-Nov-09 6:08 
GeneralRe: My vote of 2 Pin
Paulo Zemek28-Nov-09 6:29
memberPaulo Zemek28-Nov-09 6:29 
GeneralRe: My vote of 2 Pin
Miller429-Nov-09 7:21
memberMiller429-Nov-09 7:21 
GeneralSome questions [modified] Pin
Robert Rohde27-Nov-09 22:58
memberRobert Rohde27-Nov-09 22:58 
GeneralRe: Some questions Pin
Paulo Zemek28-Nov-09 6:00
memberPaulo Zemek28-Nov-09 6:00 
GeneralThe lock keyword has the same problem: don't use Thread.Abort! Pin
Daniel Grunwald27-Nov-09 9:39
memberDaniel Grunwald27-Nov-09 9:39 
GeneralRe: The lock keyword has the same problem: don't use Thread.Abort! Pin
Paulo Zemek27-Nov-09 10:05
memberPaulo Zemek27-Nov-09 10:05 
GeneralThoughts Pin
PIEBALDconsult27-Nov-09 7:50
memberPIEBALDconsult27-Nov-09 7:50 
GeneralRe: Thoughts [modified] Pin
Paulo Zemek27-Nov-09 8:04
memberPaulo Zemek27-Nov-09 8:04 
GeneralRe: Thoughts Pin
aspdotnetdev27-Nov-09 12:28
memberaspdotnetdev27-Nov-09 12:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150428.2 | Last Updated 6 Mar 2010
Article Copyright 2009 by Paulo Zemek
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid