static constructors, thread affinity, debugging

Or, perhaps a better title would be;

Why it’s better to debug with the Threads window visible”

I puzzled over something in a debugger for about 5 minutes the other day so I thought I’d share.

I had some WPF code where I had a static class in which I wanted to share a common Image which is sort of a “default image” if the class instance itself can’t find the right image to use.

So, in pseudo-code it was something like this;

    class MyClass()
    {
        static MyClass()
        {
            image = new Image(); // ...
        }
        static Image image;
    }

and that Image then goes on to be used elsewhere.

Whenever I was running this code, I was getting the familiar “You’re using the UI widget from the wrong thread” exception and I was puzzled because I thought I’d taken some care to try and not do that and I couldn’t figure out which widget it was that was complaining.

The call-stack soon showed that it was the Image above but I was really struggling to see how I’d touched the Image from anything other than my UI thread.

A bit more debugging showed that it was the other way around. The static constructor wasn’t running on my UI thread. It just so happened that I first used MyClass on a background thread and so its static constructor was running on that thread, creating an Image that my UI thread then couldn’t touch. Something a bit like this repro;

class ThreadAffinity
{
    public ThreadAffinity()
    {
        threadId = Thread.CurrentThread.ManagedThreadId;
    }
    public void SomeFunction()
    {
        if (threadId != Thread.CurrentThread.ManagedThreadId)
        {
            throw new InvalidOperationException(
               "Hey, I have thread affinity, you're on the wrong thread");
        }
    }
    int threadId;
}

static class MyClass
{
    static MyClass()
    {
        member = new ThreadAffinity();
    }
    public static void SomeFunction()    
    { 
    }
    public static ThreadAffinity Member
    {
        get
        {
            return (member);
        }
    }
    static ThreadAffinity member;
}


class Program
{ 
    static void Main(string[] args)
    {
        Thread t = new Thread(() => MyClass.SomeFunction());
        t.Start();
        t.Join();

        MyClass.Member.SomeFunction();
    }
}

You can see that I call MyClass.SomeFunction on a background thread which causes the static constructor to run on that thread and initialises the static member (with thread affinity) on that thread thereby making it pretty useless to any other thread.