Share via


Threading models

I've gotten a couple questions about why we chose the threading model we did for Avalon, especially why we didn't do more for multithreaded programs. When we first created Avalon, we had three requirements for our threading model:

  • Minimal performance cost for single threading programs
  • Minimal programming model cost for single thread programs
  • The model must be enforced, with exceptions for programs that violate the model

The performance requirements eliminated free threading. Being able to call any method from any thread seems like the obvious way to write a multithreaded UI, but it has a horrendous performance cost, because every single API call now needs to grab a lock.

But what if you could group a bunch of objects together under a single lock, and any thread can grab that lock? Well, we actually tried this for awhile, we called that the "rental" model, and its what we had in the November 2004 CTP. We learned a couple things from that. The first is that the contexts end up being fairly large -- in practice, the smallest context was the contents of a top-level window. This is because with the Avalon property engine, there's a lot of interconnection between elements, and interconnected elements need to be in the same context or else you're back to the performance problems of free threading. Another thing we found is that rental and up having a significant programming model cost for people who didn't want to do threading. We forced people to explicitly enter and leave contexts, even if they would rather not know what a "context" even is.

We also found that rental model interoperates really poorly with Win32. Win32 has thread affinity at a deep level, and if you're building upon Win32 or need to interoperate with Win32 (and Avalon does both), you have a major problem if you're using contexts -- how do you call a Win32 method if you're not on the right thread?

But the final nail in the coffin was that we didn't want to trade the devil we knew for the devil we didn't. STA and thread affinity have problems, but it's a tried and true solution that people have built many large applications on top of -- after all, its what Win32 uses. And we were seeing enough problems with rental that frankly, we thought there was a very real possibility of simply trading one set of problems for another, less understood set of problems.

So that left two options -- what we have today, which I'll call "enforced STA", and the "trust me" model. And trusting applications not to do the wrong thing, well, that ran afoul of requirement #3. Why was that a requirement? It's the same reasons we have parameter validation in all our public APIs. Because it's hard to learn how to use a system correctly if it doesn't give you feedback when you use it wrong. Because it's impossible to maintain compatibility if we don't set ground rules on what you can and can't do. And because it's quite difficult to fully spell out the rules on what's allowed and what's not, beyond what enforced STA enforces.

If anything, the situation is even worse with threading than with normal parameter validation, because if we didn't check, it would be really easy to write an application that works most of the time -- and breaks at unpredictable times. Our nightmare was trying to maintain compatibility with an application that depends on some quirk of timing. We try very hard to make every version of Windows compatible with the previous version, and that means we make no moral judgment about whether it's the application's "fault" that they don't run on the newer version -- it's our job to make it work no matter what the application did. Raymond Chen has some great stories about some of the things we've done to maintain compatibility, I have my own war stories from working in USER and GDI, and we figured compatibility is hard enough even when you enforce the rules.

So there we have it, a threading model that's tried and true, doesn't get in your face when doing single thread programs, and doesn't give you any surprises a day before shipping, yet is powerful enough to build the next Office or Windows Explorer.