I was on a mail thread today, the topic for which was the meaning—and perhaps lack of comprehensiveness—of the statement: “This type is thread safe.” Similar statements are scattered throughout our product documentation, without any good central explanation of its meaning and any caveats.
Vance Morrison’s excellent MSDN article from a few months back talks about why double checked locking is guaranteed to work on the CLR v2.0, and why it is one of the few safe lock-free mechanisms on the runtime. He also sent an email to the develop.com mailing list a while back explaining why this pattern wasn’t guaranteed to work on the ECMA memory model. We did quite a bit of implementation work and testing to tame the crazy memory model of IA-64 on 2.0. (Note that none of this is in the ECMA specification, so if you’re worried about CLI compatibility, beware.)
I’ve posted before about how you might use C# enumerators to simulate coroutines. Enumerators are a very powerful feature, but unfortunately have one big drawback vis-à-vis their attempt at coroutines: you can yield only from one stack frame deep. The C# compiler state-machine transforms enough information for a single function, but obviously doesn’t do that for the entire stack. Real coroutines can yield from an arbitrarily nested callstack, and have that entire stack restored when they are resumed.
Some fundamental changes were made in the .NET Framework 2.0 that just about obviate the need to ever write a traditional finalizer. A lot of the guidance written here is now obsolete, not because it is incorrect, but rather because there is one important new consideration to make (hosting) and a set of new tools to aid you in the task. Jeff Richter pointed this out to all of us a few months back.
Lots of people try to roll their own thread-pool. Many people have different (good) reasons for doing so.
Each Windows thread has a Thread Environment Block (i.e. TEB) which is a block
of user-mode memory pointed at and reserved for use by the Windows kernel
Thread data structure (KTHREAD). In addition to basic OS information like the
active SEH filter chain, stack base and limit, and owned critical sections,
applications can easily stash data into and retrieve data out of the Thread
Local Storage (TLS) area of the TEB. This is done using the Win32 TlsAlloc
,
TlsGetValue
, TlsSetValue
, and TlsFree
functions. You can view the TEB via the
kernel debugger’s !thread command.
Our verifier has knowledge of statically typed boxed value types. Such things
are never surfaced to user code, not even through reflection. In user code, the
type of a statically typed boxed value can only be referred to as object
,
both statically and dynamically. This is one of the nice properties of a
nominal type system; if you can’t name it, you can’t refer to it.
I’ve talked about Thread Aborts before. And I spoke briefly at PDC about why you shouldn’t lock on objects shared across AppDomains (ADs). But I wanted to spend a brief moment fusing the two together to illustrate the point. There are some interesting factors at play here.
We made a change in Whidbey recently that impacts the verification of call
s to virtual methods.
Check out Soma’s
post about the
Nullable<T>
DCR we recently implemented…we referred to the project as
nullbox
internally. This one kept me up at night on a few occassions, but was
a lot of fun. :)