Friday, March 2, 2007

.Net Threading - Synchronization Internals

Every object in the heap implicitly owns a SyncBlock datastructure pointer called SyncBlockIndex. SyncBlockIndex is a 32 bit signed integer, default value -1.

If the object is not locked-on yet, and a new lock request comes in, .Net framework allocates a SyncBlock instance (from a pool) to the object, setting the SyncBlockIndex to the appropriate index. When all locks are released, the SyncBlock is released back to the pool and the index set to a negative number.

class MyClass
{
  public void SyncOp()
  {
      lock ( this )
      {
      }
  }
}

This works well for non static object instances. But what if the object has static members?

Each object in the heap implicitly gets one more field: MethodTablePointer. MethodTablePointer points to the objects TypeDescriptor. All object instances of the same type point to the same TypeDescriptor.

Since TypeDescriptor is also an object, with its own SyncBlockIndex and TypeDescriptor, it can be used to synchronized a static object ...

class MyClass
{
  public static void SyncOp()
  {
      lock ( typeof( MyClass ) )
      {
      }
  }
}

Examples in this article do not adhere to the best practices and must not be used.

References

http://msdn.microsoft.com/msdnmag/issues/03/01/NET/