Partager via


LockManager Class

LockManager class.

Inheritance Hierarchy

System.Object
  Microsoft.TeamFoundation.Framework.Server.LockManager

Namespace:  Microsoft.TeamFoundation.Framework.Server
Assembly:  Microsoft.TeamFoundation.Framework.Server (in Microsoft.TeamFoundation.Framework.Server.dll)

Syntax

'Declaration
Public Class LockManager
public class LockManager
public ref class LockManager
type LockManager =  class end
public class LockManager

The LockManager type exposes the following members.

Constructors

  Name Description
Public method LockManager Constructor

Top

Methods

  Name Description
Public method AssertLockHeld(Object, LockManager.LockType, Int64) Assert that the given lock is held by the current thread (debug assert).
Public method AssertLockHeld(ILockName, LockManager.LockType, Int64) Assert that the given lock is held by the current thread (debug assert).
Public method AssertLockNotHeld(Object, LockManager.LockType, Int64) Assert that the given lock is not held by the current thread (debug assert).
Public method AssertLockNotHeld(ILockName, LockManager.LockType, Int64) Assert that the given lock is not held by the current thread (debug assert).
Public method AssertNoLocksHeld(Int64) Assert that the current thread holds no LockManager locks.
Public method AssertNoLocksHeld(LockManager.LockType, Int64) Assert that the given lock is not held by the current thread (debug assert).
Public method AssertZeroActiveLockObjects Asserts iff there are active locks in the lock manager (where refcount > 0)
Public methodStatic member CompareLockTypes Compares two lock types (throws if lock types are not comparable).
Public method Equals Determines whether the specified object is equal to the current object. (Inherited from Object.)
Protected method Finalize Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection. (Inherited from Object.)
Public method GetHashCode Serves as the default hash function. (Inherited from Object.)
Public method GetLock(Object, LockManager.LockType, Int64) Get a lock.
Public method GetLock(ILockName, LockManager.LockType, Int64) Get a named lock.
Public method GetType Gets the Type of the current instance. (Inherited from Object.)
Public method HasLocks Returns true if this requestId owns any locks
Public method Lock(Object, Int64) Get a leaf monitor lock for a given object.
Public method Lock(Object, LockManager.LockType, Int64) Get an object monitor lock.
Public method Lock(ILockName, LockManager.LockType, Int64) Get a named lock.
Protected method MemberwiseClone Creates a shallow copy of the current Object. (Inherited from Object.)
Public method ReleaseAnyLock Release the most nested lock of a given lock type and any name.
Public method ReleaseLock(Object, LockManager.LockType, Int64) Release a lock.
Public method ReleaseLock(ILockName, LockManager.LockType, Int64) Release a named lock.
Public method TestLock(Object, LockManager.LockType, Int64) Test if this thread already holds a lock.
Public method TestLock(String, LockManager.LockType, Int64) Test if this thread already holds a lock.
Public method ToString Returns a string that represents the current object. (Inherited from Object.)
Public method TryGetLock(Object, LockManager.LockType, Int64) Try to get a lock.
Public method TryGetLock(ILockName, LockManager.LockType, Int64, Int32) Get a named lock

Top

Remarks

Managed Store practices deadlock avoidance. All locking must use the LockManager locks. Every lock is assigned a level (a position in the locking hierarchy), and any operation can only request locks that are higher in the hierarchy than any lock currently held.

LockManager supports the concept of "named locks", e.g. when we must lock some entity for which we may not have a stable object in memory, but have just a name of such entity. Examples are mailbox and database. Any object associated with mailbox or database can come and go, all we have stable for such entity is its name, such as a database GUID for a database or mailbox number for a mailbox. We support monitor locks and reader-writer locks for named locks.

LockManager also supports ordinary "object locks", when we must lock a particular object instance in memory. Only Monitor locks are currently supported for object locks, that is the same locking mechanism as used in C# "lock" statement. In contrast to the "lock" statement, LockManager object lock fully participates in a locking hierarchy, therefore we can verify they are used in a correct order.

One special case of "object lock" is a "leaf object lock". We do not have to specify the lock level for such lock - it is expected to always be a most-nested lock and no other locks can be taken when holding such leaf lock.

"Named locks" are implemented by dynamically allocating a lock object for each unique name, and storing them in a global dictionary. Thus accessing a named lock by name requires dictionary lookup to find a corresponding lock object. The lock object dictionary should itself be locked while you perform such lookup. All this makes named locks potentially more expensive than ordinary locks, because of the additional cost of locking the dictionary and a dictionary lookup. We use two techniques to reduce such cost: (1) partitioning lock object dictionary, to reduce the dictionary global lock contention, and (2) providing caller the ability to cache the named lock object reference and bypass the dictionary lookup most of the time. Note that partitioning alone is insufficient because it does not help much with relatively wide-scope locks, such as a database lock; for example, when everybody wants to grab the same shared lock.

There is potentially unbounded number of unique lock names. Therefore, the number of named lock objects we can potentially create is also unbounded. Because references to named lock objects are stored in a global dictionary, such objects could never be automatically garbage-collected. Hence we want to be able to clean up named lock objects that are not regularly used. To support thread-safe cleanup of named lock objects, such objects are refcounted. Every lock taken on a named lock object requires having such object "addrefed", the reference should be released after lock is released. Cleanup logic checks that the object is not currently referenced before removing it from the dictionary. After a named lock object is removed from a dictionary, it is marked as disposed and cannot be addrefed any more. An attempt to lock the same name next time will cause allocating a new named lock object that has the same name and adding it back to a dictionary. Thus it is OK to have stale named lock object references cached by a caller - such stale reference will be detected and updated the next time we try to lock it and allocate a new lock object.

We use a simple time based heuristic to clean up unused lock objects. On every N named lock release calls we check if there is a time to run cleanup, and then examine the dictionary and collect all unreferenced objects which are not used recently. Then we attempt to dispose every such object and remove its reference from a dictionary. Cleanup is per dictionary partition, so that we do not have to lock other partitions when we run cleanup for any given partition.

Thread Safety

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

See Also

Reference

Microsoft.TeamFoundation.Framework.Server Namespace