Tag Archives: copy check continue

SpotTheDefect[0].Answer[1]

A couple of weeks ago I asked you to play a little game of “Spot the Defect”, and recently I posted the first of three posts with the answers, which focused on the output of the program, what the bug was and a possible way to fix it. This first fix focused on using locks to serialize access and, while locks in .Net are very fast, they are not free and prevent your application from taking full advantage of multi-core hardware. So now we are going to explore a lock free, safe alternative – but first we need to take a step back and remember how objects work in .Net (and most other Object Orientated runtimes)

Can you give me some pointers?

Usually when we code in an object orientated language and we “new up” an object we have a mental model that says that our variable contains the actual object. Similarly, if we then set that object to null, then we believe that we are removing the object from existence – but this is not the case. The variable we assigned the object to does not contain the actual object, but rather it holds a pointer to the actual object in the heap, and so setting that variable to null merely means that we are clearing the pointer, but the object will still reside in the heap until the Garbage Collector (GC) comes along to remove it. Additionally, all we need to do to ward off the GC from destroying an object is to maintain a reference (i.e. a pointer) to it.

Copy, check, continue

(There is probably already a name for this “pattern”, but I couldn’t really find it – so this will have to do. If you have a better name, or find the real name, let me know.)

So, to avoid taking locks, there are a few things that we need to do: firstly, we need to create out own reference to the object that _foo is pointing to such that we don’t have to rely on using _foo (which could become null at any time) and to prevent the GC from eating the object. The easiest way to do this is to make a copy of _foo (remember, that is copying the pointer, not the object). Which leads to my second point: once we’ve made the copy of _foo, we need to check that our copy isn’t null (because _foo has already been set to null). Finally, if our copy isn’t null, then we can continue to do whatever we planned to do.

A couple of notes about the code (you may want to come back to these after reading the code)

  • I’m using the var keyword (because I don’t really care what type _foo is, it makes maintenance easier and I’m lazy…)
  • We didn’t have to modify Thread2 at all
  • The performance overhead to Thread1 is minimal (we allocate a pointer on the stack, copy a pointer to it and then check if it is 0 – in reality the compiler will probably optimize fooLocal away and just use a register, further reducing the overhead)
  • If you were really concerned about performance, you could now drop the _disposed variable as well (since it’s not really need it)

And, finally, our updated code:

using System;
using System.Threading;

namespace SpotTheDefect1
{
    class Program
    {
        private static int _x = 0;
        private static Foo _foo = new Foo();
        private static bool _disposed = false;

        static void Main(string[] args)
        {
            Thread thread1 = new Thread(Thread1);
            Thread thread2 = new Thread(Thread2);

            thread1.Start();
            thread2.Start();

            thread1.Join();
            thread2.Join();
        }

        private static void Thread1()
        {
            if (!_disposed)
            {
                var fooLocal = _foo;
                if (fooLocal != null)
                {
                    fooLocal.Bar();
                }
            }
        }

        private static void Thread2()
        {
            Console.WriteLine("Disposing");
            _disposed = true;
            _foo = null;
        }

        private class Foo
        {
            public void Bar()
            {
                Console.WriteLine("Hello, World!");
            }
        }
    }
}
Advertisements
Tagged , , ,