2009-08-28

Q&A: If Dispose calls SuppressFinalize, is KeepAlive required?

Question: If we include a call to GC.SuppressFinalize(this) in Dispose, is the the call to GC.KeepAlive(this) still required?
Answer: No.

Rationale:

  • As has been established, a call to GC.SuppressFinalize anywhere will suppress the finalizer.
  • The object must be live at the point GC.SuppressFinalize is called because it must be passed as an argument to that method.
  • The call to GC.KeepAlive(this) was only put in Dispose to prevent the finalizer from being invoked while Dispose was still running.
  • The GC.KeepAlive(this) call is not necessary because the object will be reachable until its finalizer is suppressed.

Example requiring GC.SuppressFinalize(this)

This is almost identical to the test code used in my last Q&A: "Is a call to GC.KeepAlive(this) required in Dispose?"

// Do not run these tests from a Debug build or under the debugger. A standalone release build is required.
using System;
using System.Collections.Generic;
using System.Threading;

public class Test : IDisposable
{
    private sealed class HandleHolder
    {
        // 0 is the invalid handle value
        public int Handle { get; set; }
    }

    private HandleHolder handleHolder;

    Test()
    {
        // Set the handle to a valid value for the test
        this.handleHolder = new HandleHolder { Handle = 0x1 };
    }

    ~Test()
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": Finalizer called");
        // This is just a check to ensure the constructor completed
        if (this.handleHolder != null)
        {
            this.CloseHandle(true);
        }
    }

    // This method is pretending to be a p/Invoke function to free a handle
    static Dictionary<int, int> freedHandles = new Dictionary<int, int>();
    private static void ReleaseHandle(int handle)
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": Released handle 0x" + handle.ToString("X"));

        if (handle == 0)
        {
            Console.WriteLine("  ReleaseHandle released a bad handle! Bad, bad, bad!");
        }
        else
        {
            lock (freedHandles)
            {
                if (freedHandles.ContainsKey(handle))
                {
                    Console.WriteLine("  ReleaseHandle double-released a handle! Bad, bad, bad!");
                }
                else
                {
                    freedHandles.Add(handle, handle);
                }
            }
        }
    }

    private void CloseHandle(bool calledFromFinalizer)
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": CloseHandle starting");

        // (real code)
        HandleHolder myHandleHolder = this.handleHolder;
        if (myHandleHolder.Handle == 0)
        {
            // Handle is already free'd
            return;
        }

        // (code inserted to duplicate problems)
        if (!calledFromFinalizer)
        {
            Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
                ": Garbage collection in CloseHandle!");
            GC.Collect();
            Thread.Sleep(500); // Let the finalizer thread run
            Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
                ": CloseHandle continuing after garbage collection");
        }

        // (real code)
        ReleaseHandle(myHandleHolder.Handle);

        // (code inserted to duplicate problems)
        if (calledFromFinalizer)
        {
            // With this Thread.Sleep call, you get a double handle release
            // Without this Thread.Sleep call, you get a bad handle released
            Thread.Sleep(500); // Let the Dispose thread run    [1]
        }

        // (real code)
        myHandleHolder.Handle = 0;

        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": CloseHandle ending");
    }

    public void Dispose()
    {
        this.CloseHandle(false);
        
        // Uncomment the next line to fix the handle problems
        //GC.SuppressFinalize(this);    [2]
    }

    static void Main()
    {
        Test t = new Test();
        t.Dispose();
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": Returning from Main");
    }
}

Output with [2] commented out (as written above):

Thread 1: CloseHandle starting
Thread 1: Garbage collection in CloseHandle!
Thread 2: Finalizer called
Thread 2: CloseHandle starting
Thread 2: Released handle 0x1
Thread 1: CloseHandle continuing after garbage collection
Thread 1: Released handle 0x1
  ReleaseHandle double-released a handle! Bad, bad, bad!
Thread 1: CloseHandle ending
Thread 1: Returning from Main
Thread 2: CloseHandle ending

Output with [1] and [2] commented out:

Thread 1: CloseHandle starting
Thread 1: Garbage collection in CloseHandle!
Thread 2: Finalizer called
Thread 2: CloseHandle starting
Thread 2: Released handle 0x1
Thread 2: CloseHandle ending
Thread 1: CloseHandle continuing after garbage collection
Thread 1: Released handle 0x0
  ReleaseHandle released a bad handle! Bad, bad, bad!
Thread 1: CloseHandle ending
Thread 1: Returning from Main

Output with neither line commented out, OR with just [1] commented out:

Thread 1: CloseHandle starting
Thread 1: Garbage collection in CloseHandle!
Thread 1: CloseHandle continuing after garbage collection
Thread 1: Released handle 0x1
Thread 1: CloseHandle ending
Thread 1: Returning from Main

Q&A: Is a call to GC.KeepAlive(this) required in Dispose?

Question: Is a call to GC.KeepAlive(this) required in Dispose?
Answer: Only in pathological cases.

Rationale:

  • Dispose() must be safe to call multiple times.
  • To prevent multiple disposal of unmanaged resources, there must exist some kind of object-level flag (e.g., "bool disposed") or state (e.g., an invalid handle value) to detect if the object has been disposed.
  • This flag must be set by Dispose (or a method invoked by Dispose) after it is checked.
  • If the flag is set after disposing the unmanaged resource, then it acts as an equivalent to GC.KeepAlive(this).
  • This flag must be checked by the finalizer (or a method invoked by the finalizer).
  • If the flag is set before disposing the unmanaged resource, it is still set after it has been checked.
  • The concurrency rules for the Microsoft CLR guarantee that this is safe for any reasonable type of flag (bool, IntPtr, or reference type).
  • Therefore, GC.KeepAlive(this) is only required if the flag is of a very unusual type (such as a Double) OR if the flag is inside another object.

This reasoning concludes that for 99% of handle objects, a call to GC.KeepAlive(this) is not required. Furthermore, for 99% of the remaining objects, a call to GC.SuppressFinalize should be used instead of a call to GC.KeepAlive.

Example 1 not requiring GC.KeepAlive(this)

This example uses a "bool disposed" flag, set before disposing the unmanaged resource:

// Do not run these tests from a Debug build or under the debugger. A standalone release build is required.
private bool disposed;

~Test()
{
    if (!this.disposed)
    {
        this.CloseHandle();
    }
}

public void Dispose()
{
    if (!this.disposed)
    {
        // At this point, if a GC occurs, the object is still reachable

        this.disposed = true;

        // This is the soonest point that a GC can occur calling this object's finalizer
        //  and this.disposed has already been set to true.

        this.CloseHandle();
    }
}

Example 2 not requiring GC.KeepAlive(this)

This example uses a "bool disposed" flag, set after disposing the unmanaged resource:

// Do not run these tests from a Debug build or under the debugger. A standalone release build is required.
private bool disposed;

~Test()
{
    if (!this.disposed)
    {
        this.CloseHandle();
    }
}

public void Dispose()
{
    if (!this.disposed)
    {
        this.CloseHandle();

        // At this point, if a GC occurs, the object is still reachable

        this.disposed = true;

        // This is the soonest point that a GC can occur calling this object's finalizer
        //  and this.disposed has already been set to true.
    }
}

Example 3 not requiring GC.KeepAlive(this)

This example uses an "invalid handle" flag:

// Do not run these tests from a Debug build or under the debugger. A standalone release build is required.
private IntPtr handle;

~Test()
{
    if (this.handle != IntPtr.Zero)
    {
        this.CloseHandle();
    }
}

public void Dispose()
{
    if (this.handle != IntPtr.Zero)
    {
        this.CloseHandle();

        // At this point, if a GC occurs, the object is still reachable

        this.handle = IntPtr.Zero;

        // This is the soonest point that a GC can occur calling this object's finalizer
        //  and this.handle has already been set to IntPtr.Zero.
    }
}

Example 4 - requiring GC.KeepAlive(this)

It is possible to create a more pathological case where GC.KeepAlive(this) is required; the code below requires GC.KeepAlive because it holds its actual handle value inside of another class:

// Do not run these tests from a Debug build or under the debugger. A standalone release build is required.
using System;
using System.Collections.Generic;
using System.Threading;

public class Test : IDisposable
{
    private sealed class HandleHolder
    {
        // 0 is the invalid handle value
        public int Handle { get; set; }
    }

    private HandleHolder handleHolder;

    Test()
    {
        // Set the handle to a valid value for the test
        this.handleHolder = new HandleHolder { Handle = 0x1 };
    }

    ~Test()
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": Finalizer called");
        // This is just a check to ensure the constructor completed
        if (this.handleHolder != null)
        {
            this.CloseHandle(true);
        }
    }

    // This method is pretending to be a p/Invoke function to free a handle
    static Dictionary<int, int> freedHandles = new Dictionary<int, int>();
    private static void ReleaseHandle(int handle)
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": Released handle 0x" + handle.ToString("X"));

        if (handle == 0)
        {
            Console.WriteLine("  ReleaseHandle released a bad handle! Bad, bad, bad!");
        }
        else
        {
            lock (freedHandles)
            {
                if (freedHandles.ContainsKey(handle))
                {
                    Console.WriteLine("  ReleaseHandle double-released a handle! Bad, bad, bad!");
                }
                else
                {
                    freedHandles.Add(handle, handle);
                }
            }
        }
    }

    private void CloseHandle(bool calledFromFinalizer)
    {
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": CloseHandle starting");

        // (real code)
        HandleHolder myHandleHolder = this.handleHolder;
        if (myHandleHolder.Handle == 0)
        {
            // Handle is already free'd
            return;
        }

        // (code inserted to duplicate problems)
        if (!calledFromFinalizer)
        {
            Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
                ": Garbage collection in CloseHandle!");
            GC.Collect();
            Thread.Sleep(500); // Let the finalizer thread run
            Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
                ": CloseHandle continuing after garbage collection");
        }

        // (real code)
        ReleaseHandle(myHandleHolder.Handle);

        // (code inserted to duplicate problems)
        if (calledFromFinalizer)
        {
            // With this Thread.Sleep call, you get a double handle release
            // Without this Thread.Sleep call, you get a bad handle released
            Thread.Sleep(500); // Let the Dispose thread run     [1]
        }

        // (real code)
        myHandleHolder.Handle = 0;

        // If you uncomment the next line, then you won't get handle release errors
        //  regardless of the Thread.Sleep above.
        //GC.KeepAlive(this);     [2]

        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": CloseHandle ending");
    }

    public void Dispose()
    {
        this.CloseHandle(false);
    }

    static void Main()
    {
        Test t = new Test();
        t.Dispose();
        Console.WriteLine("Thread " + Thread.CurrentThread.ManagedThreadId +
            ": Returning from Main");
    }
}

Output with [2] commented out (as written above):

Thread 1: CloseHandle starting
Thread 1: Garbage collection in CloseHandle!
Thread 2: Finalizer called
Thread 2: CloseHandle starting
Thread 2: Released handle 0x1
Thread 1: CloseHandle continuing after garbage collection
Thread 1: Released handle 0x1
  ReleaseHandle double-released a handle! Bad, bad, bad!
Thread 1: CloseHandle ending
Thread 1: Returning from Main
Thread 2: CloseHandle ending

Output with [1] and [2] commented out:

Thread 1: CloseHandle starting
Thread 1: Garbage collection in CloseHandle!
Thread 2: Finalizer called
Thread 2: CloseHandle starting
Thread 2: Released handle 0x1
Thread 2: CloseHandle ending
Thread 1: CloseHandle continuing after garbage collection
Thread 1: Released handle 0x0
  ReleaseHandle released a bad handle! Bad, bad, bad!
Thread 1: CloseHandle ending
Thread 1: Returning from Main

Output with neither line commented out, OR with just [1] commented out:

Thread 1: CloseHandle starting
Thread 1: Garbage collection in CloseHandle!
Thread 1: CloseHandle continuing after garbage collection
Thread 1: Released handle 0x1
Thread 1: CloseHandle ending
Thread 1: Returning from Main
Thread 2: Finalizer called
Thread 2: CloseHandle starting

Closing Notes

It is cleaner and more efficient to include a call to GC.SuppressFinalize(this) instead of a call to GC.KeepAlive(this). The only true reason a call to GC.KeepAlive should be required is if the disposed flag is of an unusual type (like Double).

Q&A: Can GC.SuppressFinalize(this) be called at any time?

Today I was asked by a colleague about some of my blog posts yesterday regarding IDisposable and Finalize. So here's the first post in a series of Q&A regarding finalizers. Enjoy!

Question: Does GC.SuppressFinalize(this) work if the object is not already on the finalize queue?
Answer: Yes, it does.

Additional Information

There's some confusion on what exactly GC.SuppressFinalize does, because the .NET 1.1 docs state "The method removes obj from the set of objects that require finalization." However, since .NET 2.0, the docs have been updated to read "This method sets a bit in the object header, which the system checks when calling finalizers." This clarifies GC.SuppressFinalize semantics nicely.

Because of the old docs, there is some FUD regarding GC.SuppressFinalize floating around in old forum and newsgroup posts. Some people insist that it must be the last thing done by a Dispose() implementation. However, the truth is that it is safe to call at any time. In fact, some BCL classes even call GC.SuppressFinalize in their constructors!

There is an argument that can be made for calling GC.SuppressFinalize as the last statement in a Dispose method: it ensures that the finalizer is only suppressed if Dispose does not throw. However, it is very poor practice to have a Dispose method that throws, so this argument has little merit.

Test Code:

// Do not run these tests from a Debug build or under the debugger. A standalone release build is required.
using System;
using System.Threading;
using System.Diagnostics;

public class Test : IDisposable
{
    public static Test test;

    ~Test()
    {
        Console.WriteLine("Finalizer called");
    }

    public void RemoveMyFinalizer()
    {
        GC.SuppressFinalize(this);
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose called");
    }

    public void Report()
    {
        Console.WriteLine("Test object is still alive!");
    }

    static void Main()
    {
        // We use a static object here to ensure it is reachable
        Test.test = new Test();
        // Since the test object is reachable, it cannot be in the finalizer queue at this point
        Test.test.RemoveMyFinalizer();
        Test.test.Report();
        Console.WriteLine("Returning from Main");
    }
}

Output of Test Code:

Test object is still alive!
Returning from Main

2009-08-27

The Third Rule of Implementing IDisposable and Finalizers

This post is part of How to Implement IDisposable and Finalizers: 3 Easy Rules.

For a class owning a single unmanaged resource, implement IDisposable and a finalizer

A class that owns a single unmanaged resource should not be responsible for anything else. It should only be responsible for closing that resource.

No classes should be responsible for multiple unmanaged resources. It's hard enough to properly free a single resource; writing a class that handles multiple unmanaged resources is much more difficult.

No classes should be responsible for both managed and unmanaged resources. It's possible to write a class that handles both unmanaged and managed resource, but this is extremely difficult to code correctly. Trust me; don't go there. Even if the class is bug-free, it's a maintenance nightmare. Microsoft re-wrote a lot of core classes in the BCL when .NET 2.0 came out, specifically so they could divide the classes with unmanaged resources from the classes with managed resources.

Note: a lot of the really overly-complex Microsoft IDisposable documentation is because they assume your class will want to handle both managed and unmanaged resources. This is a holdover from .NET 1.0, and it's kept only for backwards compatibility. Take a clue from Microsoft: their own classes don't even follow that old pattern (they were changed in .NET 2.0 to follow the pattern described in this blog post). FxCop will yell at you because you need to implement IDisposable "correctly" (i.e., using the old pattern); ignore it - FxCop is wrong.

The class should look something like this:

// This is an example of a correct IDisposable implementation.
// It is not ideal, however, because it does not inherit from SafeHandle
public sealed class WindowStationHandle : IDisposable
{
    public WindowStationHandle(IntPtr handle)
    {
        this.Handle = handle;
    }

    public WindowStationHandle()
        : this(IntPtr.Zero)
    {
    }

    public bool IsInvalid
    {
        get { return (this.Handle == IntPtr.Zero); }
    }

    public IntPtr Handle { get; set; }

    private void CloseHandle()
    {
        // Do nothing if the handle is invalid
        if (this.IsInvalid)
        {
            return;
        }

        // Close the handle, logging but otherwise ignoring errors
        if (!NativeMethods.CloseWindowStation(this.Handle))
        {
            Trace.WriteLine("CloseWindowStation: " + new Win32Exception().Message);
        }

        // Set the handle to an invalid value
        this.Handle = IntPtr.Zero;
    }

    public void Dispose()
    {
        this.CloseHandle();
        GC.SuppressFinalize(this);
    }

    ~WindowStationHandle()
    {
        this.CloseHandle();
    }
}

internal static partial class NativeMethods
{
    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool CloseWindowStation(IntPtr hWinSta);
}

IDisposable.Dispose ends with a call to GC.SuppressFinalize(this). This ensures that the object will remain live until after its finalizer has been suppressed.

If Dispose is not explicitly invoked, then the finalizer will eventually be invoked, which calls CloseHandle directly.

CloseHandle first checks if the handle is invalid. Then it closes the handle, being careful not to throw exceptions; CloseHandle may be called from the finalizer, and an exception at that point would crash the process. CloseHandle finishes by marking the handle as invalid, making it safe to invoke this method multiple times; this, in turn, makes it safe to invoke Dispose multiple times. It is possible to move this "validity check" into the Dispose method, but placing it in CloseHandle also allows invalid handles to be passed into the constructor or set in the Handle property.

The only reason that SuppressFinalize is called after CloseHandle is because this allows the finalizer to run if the Dispose's CloseHandle fails (by throwing an exception). This is discussed in detail on Joe Duffy's blog, but is a relatively weak argument; the only way this would really make a difference is if the CloseHandle method closed the handle differently when invoked by the finalizer. While it is possible to write code like this, it is certainly not recommended.

Important! The WindowStationHandle class does not obtain a window station handle; it knows nothing of creating or opening window stations. That responsibility (along with all the other window station-related methods) belongs in another class (presumably named "WindowStation"). This helps create a correct implementation, because every finalizer must be able to execute without error on a partially-constructed object if the constructor throws; in practice, this is very difficult, and this is another reason why a wrapper class should be split into a "handle closer" class and a "proper wrapper" class.

Note: this is the simplest possible solution, and it does have some very obscure resource leaks (e.g., if a thread is aborted immediately after returning from a resource allocation function). If you're developing on the full framework, and are wrapping an IntPtr handle (such as the window station example above), then it is better to derive from SafeHandle. If you need to go a step further and support reliable resource deallocation, things get very complex very quickly!

This post is part of How to Implement IDisposable and Finalizers: 3 Easy Rules.

The Second Rule of Implementing IDisposable and Finalizers

This post is part of How to Implement IDisposable and Finalizers: 3 Easy Rules.

For a class owning managed resources, implement IDisposable (but not a finalizer)

IDisposable only has one method: Dispose. This method has one important guarantee: it must be safe to call multiple times.

An implementation of Dispose may assume that it is not called from a finalizer thread, that its instance is not being garbage collected, and that a constructor for its instance has completed successfully. These assumptions makes it safe to access other managed objects.

One mistake is to place a finalizer on a class that only has managed resources; this example code can result in an exception on the finalizer thread, which would crash the application:

// This is an example of an incorrect and buggy finalizer.
public sealed class SingleApplicationInstance
{
    private Mutex namedMutex;
    private bool namedMutexCreatedNew;

    public SingleApplicationInstance(string applicationName)
    {
        this.namedMutex = new Mutex(false, applicationName, out namedMutexCreatedNew);
    }

    public bool AlreadyExisted
    {
        get { return !this.namedMutexCreatedNew; }
    }

    ~SingleApplicationInstance()
    {
        // Bad, bad, bad!!!
        this.namedMutex.Close();
    }
}

Whether or not SingleApplicationInstance implements IDisposable, the fact that it's accessing a managed object in its finalizer is a recipe for disaster.

Here's an exmple of a class that removes the finalizer and then implements IDisposable in a correct but needlessly complex way:

// This is an example of a needlessly complex IDisposable implementation.
public sealed class SingleApplicationInstance : IDisposable
{
    private Mutex namedMutex;
    private bool namedMutexCreatedNew;

    public SingleApplicationInstance(string applicationName)
    {
        this.namedMutex = new Mutex(false, applicationName, out namedMutexCreatedNew);
    }

    public bool AlreadyExisted
    {
        get { return !this.namedMutexCreatedNew; }
    }

    // Needlessly complex
    public void Dispose()
    {
        if (namedMutex != null)
        {
            namedMutex.Close();
            namedMutex = null;
        }
    }
}

When a class owns managed resources, it may forward its Dispose call on to them. No other code is necessary. Remember that some classes rename "Dispose" to "Close", so a Dispose implementation may consist entirely of calls to Dispose and Close methods.

An equivalent - and simpler - implementation is here:

// This is an example of a correct IDisposable implementation.
public sealed class SingleApplicationInstance : IDisposable
{
    private Mutex namedMutex;
    private bool namedMutexCreatedNew;

    public SingleApplicationInstance(string applicationName)
    {
        this.namedMutex = new Mutex(false, applicationName, out namedMutexCreatedNew);
    }

    public bool AlreadyExisted
    {
        get { return !this.namedMutexCreatedNew; }
    }

    public void Dispose()
    {
        namedMutex.Close();
    }
}

This IDisposable.Dispose implementation is perfectly safe. It can be safely called multiple times, because each of the IDisposable implementations it invokes can be safely called multiple times. This transitive property of IDisposable should be used to write simple Dispose implementations like this one.

This post is part of How to Implement IDisposable and Finalizers: 3 Easy Rules.

The First Rule of Implementing IDisposable and Finalizers

This post is part of How to Implement IDisposable and Finalizers: 3 Easy Rules.

Don't do it (unless you need to).

IDisposable is not a destructor. Remember that .NET has a garbage collector that works just fine without requiring you to set member variables to null.

There are only two situations when IDisposable does need to be implemented; apply these tests to a class to determine if IDisposable is needed:

  • The class owns unmanaged resources.
  • The class owns managed (IDisposable) resources.

Note that only classes that own resources should free them. In particular, a class may have a reference to a shared resource; in this case, it should not free the resource because other classes may still be using it.

Here's a code example similar to what many beginner C# programmers write:

// This is an example of an incorrect IDisposable implementation.
public sealed class ErrorList : IDisposable
{
    private string category;
    private List<string> errors;

    public ErrorList(string category)
    {
        this.category = category;
        this.errors = new List<string>();
    }

    // (other methods go here to add/display error messages)

    // Completely unnecessary...
    public void Dispose()
    {
        if (this.errors != null)
        {
            this.errors.Clear();
            this.errors = null;
        }
    }
}

Some programmers (especially with C++ backgrounds) even go a step further and add a finalizer:

// This is an example of an incorrect and buggy IDisposable implementation.
public sealed class ErrorList : IDisposable
{
    private string category;
    private List<string> errors;

    public ErrorList(string category)
    {
        this.category = category;
        this.errors = new List<string>();
    }

    // (other methods go here to add/display error messages)

    // Completely unnecessary...
    public void Dispose()
    {
        if (this.errors != null)
        {
            this.errors.Clear();
            this.errors = null;
        }
    }

    ~ErrorList()
    {
        // Very bad!
        // This can cause an exception in the finalizer thread, crashing the application!
        this.Dispose();
    }
}

The correct implementation of IDisposable for this type is here:

// This is an example of a correct IDisposable implementation.
public sealed class ErrorList
{
    private string category;
    private List<string> errors;

    public ErrorList(string category)
    {
        this.category = category;
        this.errors = new List<string>();
    }
}

That's right, folks. The correct IDisposable implementation for this class is to not implement IDisposable! When an ErrorList instance becomes unreachable, the garbage collector will automatically reclaim all of its memory and resources.

Remember the two tests to determine if IDisposable is needed (owning unmanaged resources and owning managed resources). A simple checklist can be done as follows:

  1. Does the ErrorList class own unmanaged resources? No, it does not.
  2. Does the ErrorList class own managed resources? Remember, "managed resources" are any classes implementing IDisposable. So, check each owned member type:
    1. Does string implement IDisposable? No, it does not.
    2. Does List<string> implement IDisposable? No, it does not.
    3. Since none of the owned members implement IDisposable, the ErrorList class does not own any managed resources.
  3. Since there are no unmanaged resources and no managed resources owned by ErrorList, it does not need to implement IDisposable.

This post is part of How to Implement IDisposable and Finalizers: 3 Easy Rules.

How to Implement IDisposable and Finalizers: 3 Easy Rules

Microsoft's documentation on IDisposable is needlessly confusing. It really boils down to three simple rules.

Rule 1: Don't do it (unless you need to).

There are only two situations when IDisposable does need to be implemented:

  • The class owns unmanaged resources.
  • The class owns managed (IDisposable) resources.

See The First Rule of Implementing IDisposable and Finalizers for more details.

Rule 2: For a class owning managed resources, implement IDisposable (but not a finalizer)

This implementation of IDisposable should only call Dispose for each owned resource. It should not have any other code: no "if" statements, no setting anything to null; just calls to Dispose or Close.

The class should not have a finalizer.

See The Second Rule of Implementing IDisposable and Finalizers for more details.

Rule 3: For a class owning a single unmanaged resource, implement both IDisposable and a finalizer

A class that owns a single unmanaged resource should not be responsible for anything else. It should only be responsible for closing that resource.

No class should be responsible for multiple unmanaged resources.

No class should be responsible for both managed and unmanaged resources.

This implementation of IDisposable should call an internal "CloseHandle" method and then end with a call to GC.SuppressFinalize(this).

The internal "CloseHandle" method should close the handle if it is a valid value, and then set the handle to an invalid value. This makes "CloseHandle" (and therefore Dispose) safe to call multiple times.

The finalizer for the class should just call "CloseHandle".

See The Third Rule of Implementing IDisposable and Finalizers for more details.

Finalizers at Process Exit

I spent too long investigating a problem in a colleague's code today; the bug was something I knew about but had forgotten:

During process shutdown, finalizers are given a strict timeout. If they overrun their timeout, the process is terminated.

This can easily happen if, say, someone you work with writes a program that leaves cleaning up database objects to the finalizers. The program works fine with their small test databases, but then seems to have no effect when used with larger databases (database engines tend to get excited and roll back operations when their client programs suddenly terminate).

I can't believe that I spent over an hour today tracking this down (sigh). So, I researched it out in some depth, and collected wisdom from several others below.

Supporting Statements

"Finalization during process termination will eventually timeout." (Chris Brumme, Finalization).

"We run most of the above shutdown under the protection of a watchdog thread. By this I mean that the shutdown thread signals the finalizer thread to perform most of the above steps. Then the shutdown thread enters a wait with a timeout. If the timeout triggers before the finalizer thread has completed the next stage of the managed shutdown, the shutdown thread wakes up and skips the rest of the managed part of the shutdown." (Chris Brumme, Startup, Shutdown and related matters).

"[When a process is gracefully terminating], each Finalize method is given approximately 2 seconds to return. If a Finalize method doesn't return within 2 seconds, the CLR just kills the process - no more Finalize methods are called. Also, if it takes more than 40 seconds to call all objects' Finalize methods, then again, the CLR just kills the process. Note: These timeout values were correct at the time I wrote this text, but Microsoft might change them in the future." (Jeffrey Richter, Applied Microsoft .NET Framework Programming, pg 467; and CLR via C#, 2nd ed, pg 478).

2009-08-20

BarCampGR4 Slides Available

The slides for my talk, "Designing Application Protocols for TCP/IP" are now available. I'll be giving this talk either Friday night or Saturday sometime.

If you're from Northern Michigan, stop on by!

Where Has Steve Been?

For those of you who are wondering why I haven't been blogging much the last few weeks, the biggest reason is right here - our first baby! He does keep us up at night, but he makes up for it by being cute!

The other reason is that I'm preparing to give my first programming-related presentation ever. It will be on TCP/IP application protocol design, and will be given at BarCamp Grand Rapids 4 this weekend. I'll post a link to the slides sometime in the next few days.

2009-08-17

Alternative GUIDs for mobile devices using SQL Server Compact

This is a bit of an obscure topic, but something I had to work on recently. A company I work for does a lot of mobile (compact framework) projects, and all of them use SQL Server CE to store collected data in a database. This data is later synchronized up to a central machine. The synchronization (and other data access) right now is very slow on the devices, since they are using the same code for data access as the desktop applications. As part of a re-thinking of the data layer, I came up with a new type of GUID.

Anatomy of a Normal GUID and SqlGuid

The problem is that SQL Server Compact Edition does not support newsequentialid(), so I experimented with finding a replacement. UuidCreateSequential is not supported on CE/WM (though there have been some reports of people getting it working), so I decided to write my own GUID generation algorithm.

Design Constraints

  • The system clock should be considered particularly unreliable; handheld devices often reset their time to a "zero point" after a hard reset.
  • The presence of a MAC address can be assumed. All devices have the ability of network connectivity, though not always connected.
  • However, the MAC address should not directly be placed in the result, due to security concerns.
  • Efficiency of GUID generation is not a high concern; the goal is to produce sequential GUIDs that work well with SQL server indexing.
  • Be RFC 4122 conforming if possible.

Considering RFC 4122 Conformity

The version 1 and 4 GUIDs are quite well known. Version 1 is unacceptable because of the exposure of the MAC address, although a 47-bit random number can be substituted. Version 4 does not have a sequential variant because it is fully random. Versions 3 and 5 are name-based GUIDs, but they use one-way hashing, so they are also not sequential.

It is possible to use a RFC 4122 Version 1 GUID if the MAC address is replaced with a 47-bit random "node" number. However, the SQL Server ordering does not work nicely with the byte ordering of the timestamp in a Version 1 GUID; this is why the newsequentialid() function reverses the bytes in the first group. Technically, this makes it non-RFC 4122-conforming, but if we're going to set RFC 4122 aside, could we make a better GUID? All bits in an RFC 4122 GUID are either used or reserved, so we're going to start from scratch with a completely incompatible GUID structure.

An Alternative GUID

  • The two most-significant bits are used for the version:
    • Version 0 is a MAC-based sequential GUID.
    • Version 1 is a random-based sequential GUID.
    • Versions 2-3 are reserved.
  • We can generate a (system-wide) node value by hashing the lowest MAC address, or a 46-bit random value if the MAC address is unavailable. This should be changed whenever the MAC address changes.
    • This creates a natural grouping "by source node" in SQL server.
  • The clock sequence is similar to RFC 4122, only it is 20 bits instead of 14 bits, due to the higher possibility of clock resets in handheld devices.
    • The clock sequence is incremented when the current timestamp is less than the last timestamp.
    • The clock sequence is initialized to a random value when the node value changes (or is first calculated).
    • This creates a subgrouping "by run" in SQL server.
  • Timestamp is a 60-bit value identical to RFC 4122. The timestamp must be stored in a system-wide location.
    • This creates a subgrouping "by time" in SQL server.
  • All fields are stored in little-endian instead of big-endian, to maximize the efficiency of SQL server's comparision algorithm.

Non-volatile storage needs:

  • Lowest MAC address on the device, and its hash; or, the random value used in place of the hash.
  • Last clock sequence value.
  • Last timestamp generated.

Implementation notes:

  • RNGCryptoServiceProvider may be used for random number generation.
  • Guid or SqlGuid may be used to hold the result.
  • TimeSpan.Ticks may be used for timestamp calculations.
  • There is no support for reading the MAC address; we'd have to p/Invoke iphlpapi.dll|GetAdaptersInfo.
  • We would need a platform-specific method for non-volatile storage.
  • There is no support for named mutexes. We can p/Invoke CreateMutex from coredll.dll (using them as a WaitHandle instead of an unmanaged wait).

Final Words

This is just a rough draft of a replacement GUID design. These GUIDs are designed specifically for use as primary keys in a SQL Server database; they are not guaranteed to be unique when compared with normal GUIDs.

Another application I'm working on is using the excellent ESENT embedded database built into Windows 2000 and higher (it's a portable application, so SQL Server CE isn't usable). ESENT has its own GUID ordering which is different than SQL Server, so I'll probably be using this GUID design with a different byte ordering on that platform.

2009-08-14

Gotchas from SynchronizationContext!

This week, I've been designing a SynchronizationContext equivalent for the Compact Framework as groundwork for sharing a layer of asynchronous service objects between desktop and mobile applications. I ran into two difficulties with its semantics. I've encountered both of these before, but now that I'm designing something nearly equivalent, I'm trying to fix them before they cause problems for others.

Gotcha #1: Reentrancy

Did you know that SynchronizationContext.Send can directly invoke the delegate argument? You did? Ah, yes... the default implementation, mscorlib.dll:System.Threading.SynchronizationContext.Send does indeed invoke its delegate argument directly. This is a slightly obscure but not unheard-of fact.

Now for the one that surprised me this week: SynchronizationContext.Post can also directly invoke its delegate argument! The evidence is in System.Web.dll:System.Web.AspNetSynchronizationContext.Post, which invokes its delegate argument directly.

A careful reading of the SynchronizationContext documentation leads me to conclude that both Send and Post may result in reentrant behavior. Previously, I had assumed that Post (at least) would not be reentrant.

If code for an asynchronous component needs to prevent reentrancy from a generic SynchronizationContext, it may easily do so by using the ThreadPool:

/// 
/// Provides extension methods for .
/// 
public static class SynchronizationContextExtensions
{
    /// 
    /// Synchronously invokes a delegate by passing it to a , waiting for it to complete.
    /// 
    /// The  to pass the delegate to. May not be null.
    /// The delegate to invoke. May not be null.
    /// 
    /// This method is guaranteed to not be reentrant.
    /// 
    public static void SafeSend(this SynchronizationContext synchronizationContext, Action action)
    {
        // The semantics of SynchronizationContext.Send allow it to invoke the delegate directly, but we can't allow that.
        Action forwardDelegate = () => synchronizationContext.Send((state) => action(), null);
        IAsyncResult result = forwardDelegate.BeginInvoke(null, null);
        result.AsyncWaitHandle.WaitOne();
    }

    /// 
    /// Asynchronously invokes a delegate by passing it to a , returning immediately.
    /// 
    /// The  to pass the delegate to. May not be null.
    /// The delegate to invoke. May not be null.
    /// 
    /// This method is guaranteed to not be reentrant.
    /// 
    public static void SafePost(this SynchronizationContext synchronizationContext, Action action)
    {
        // The semantics of SynchronizationContext.Post allow it to invoke the delegate directly, but we can't allow that.
        ThreadPool.QueueUserWorkItem((state) => synchronizationContext.Post((state2) => action(), null));
    }
}

This code or something similar may go into the next release of Nito.Async. However, the code as-is will cause a deadlock when used with synchronization contexts that are sometimes reentrant (e.g., WindowsFormsSynchronizationContext.Send or DispatcherSynchronizationContext.Send if called from the specific thread associated with that synchronization context).

Gotcha #2: Non-exclusive execution

SynchronizationContext does not guarantee that delegates queued to it will be executed exclusively (one at a time). This is obvious; the default implementation (using the ThreadPool) will simply queue them to the ThreadPool, which will execute them in parallel.

However, this brings up concerns when designing APIs for asynchronous components. In particular, cancellation becomes problematic.

Some SynchronizationContext instances do execute exclusively: the WindowsFormsSynchronizationContext, DispatcherSynchronizationContext and Nito.Async.ActionDispatcherSynchronizationContext all operate on some type of queue internally, which has a single thread processing requests one at a time.

Most asynchronous components that use the event-based asynchronous pattern (EBAP) - including Nito.Async classes - assume that SynchronizationContext will actually synchronize the delegates with some notion of an "originating thread". However, this is only true for SynchronizationContext instances that execute exclusively. So it works in most cases (Windows Forms, WPF, and explicit ActionDispatcher queues), but would fail in other cases (most notably ASP.NET and in free-threaded/ThreadPool contexts).

There does not appear to be an EBAP solution that is Clean (keeping the EBAP design), Generic (working with any SynchronizationContext), and Safe (preventing event callbacks after cancellation). In fact, this is another manifestation of the "thread-safe" events problem.

One approach is to break the EBAP design by passing callbacks to the OperationAsync method; a callback delegate can be made cancelable, returning an "ICancelable" to the caller. By enclosing the callback in a cancelable object, we can introduce a lock scope just for that single callback and its canceller. A (recursive) lock could be held during the delegate invokation and requested by ICancelable.Cancel; normally, holding locks during callbacks is A Fast Road To Pain, but with careful implementation it would work in this instance. This would be a Generic and Safe solution (works with any SynchronizationContext and guarantees not to invoke a callback after ICancelable.Cancel returns). Further development down this design path would yield something very similar to the Task class expected to be in .NET 4.0.

A second approach is to break thread safety by using "thread-safe events", wrong solution #2: the EBAP component can queue a delegate that executes the OperationCompleted event from the component after copying it into a local variable. Cancelling the notification is possible by clearing the event, but the race condition means that the notification may be invoked after OperationCancel returns. This solution is Clean and Generic (keeps the OperationCompleted event on the EBAP class and works with any SynchronizationContext). Also, this solution is Safe as long as the SynchronizationContext executes exclusively.

The third approach is to only support SynchronizationContext instances that execute exclusively. This approach is the one currently taken by Nito.Async EBAP components: each delegate is assumed to be synchronized when it is queued to the SynchronizationContext, and uses a callback context to determine if it has been cancelled. This solution is Clean and Safe (keeping the OperationCompleted event on the EBAP class and guarantees not to invoke it after OperationCancel returns).

The future

I'm a big fan of quiet cancellation over noisy cancellation. If I call "Cancel", then I don't need an event to tell me that I just called "Cancel". The entire Nito.Async library works on the same (quiet cancellation) principle. However, if noisy cancellation is embraced, then the Safe issue goes away (because noisy cancellation EBAP components cannot be Safe, by definition).

Perhaps - just perhaps - the next version of Nito.Async will change to use noisy cancellation semantics. I'm still exploring alternatives. :)