Lock Class
Definition
Important
Some information relates to prerelease product that may be substantially modified before it’s released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
Provides a mechanism for achieving mutual exclusion in regions of code between different threads.
public ref class Lock sealed
public sealed class Lock
type Lock = class
Public NotInheritable Class Lock
- Inheritance
-
Lock
Remarks
The Lock class can be used to define regions of code that require mutually exclusive access between threads of a process, commonly called critical sections, to prevent concurrent accesses to a resource. A Lock
can be entered and exited, where the region of code between the enter and exit is a critical section associated with the lock. A thread that enters a lock is said to hold or own the lock until it exits the lock. At most one thread can hold a lock at any given time. A thread can hold multiple locks. A thread can enter a lock multiple times before exiting it, such as recursively. A thread that can't enter a lock immediately can wait until the lock can be entered or until a specified timeout expires.
When using the Enter or TryEnter methods to enter a lock:
- Ensure that the thread exits the lock with Exit even in case of exceptions, such as in C# by using a
try/finally
block. - When the lock is being entered and exited in a C#
async
method, ensure that there is noawait
between the enter and exit. Locks are held by threads and the code following anawait
might run on a different thread.
It is recommended to use the EnterScope method with a language construct that automatically disposes the returned Lock.Scope such as the C# using
keyword, or to use the C# lock
keyword, as these ensure that the lock is exited in exceptional cases. These patterns might also have performance benefits over using Enter/TryEnter
and Exit
. The following code fragment illustrates various patterns for entering and exiting a lock.
public sealed class ExampleDataStructure
{
private readonly Lock _lockObj = new();
public void Modify()
{
lock (_lockObj)
{
// Critical section associated with _lockObj
}
using (_lockObj.EnterScope())
{
// Critical section associated with _lockObj
}
_lockObj.Enter();
try
{
// Critical section associated with _lockObj
}
finally { _lockObj.Exit(); }
if (_lockObj.TryEnter())
{
try
{
// Critical section associated with _lockObj
}
finally { _lockObj.Exit(); }
}
}
}
When using the C# lock
keyword or similar to enter and exit a lock, the type of the expression must be precisely System.Threading.Lock
. If the type of the expression is anything else, such as Object
or a generic type like T
, a different implementation that is not interchangeable can be used instead (such as Monitor). For more information, see the relevant compiler speclet.
Interrupt can interrupt threads that are waiting to enter a lock. On Windows STA threads, waits for locks allow message pumping that can run other code on the same thread during a wait. Some features of the waits can be overridden by a custom SynchronizationContext.
Note
A thread that enters a lock, including multiple times such as recursively, must exit the lock the same number of times to fully exit the lock and allow other threads to enter the lock. If a thread exits while holding a Lock
, the behavior of the Lock
becomes undefined.
Caution
If, on a code path, a thread might enter multiple locks before exiting them, ensure that all code paths that might enter any two of those locks on the same thread enter them in the same order. Otherwise, it could lead to deadlocks. For example, consider that on one code path thread T1
enters lock L1
then lock L2
before exiting both, and on another code path thread T2
enters both locks in the inverse order. In that scenario, it would be possible for the following order of events to occur: T1
enters L1
, T2
enters L2
, T1
tries to enter L2
and waits, T2
tries to enter L1
and waits. There's a deadlock between T1
and T2
that can't be resolved, and any other threads that try to enter either lock in the future will also hang.
Constructors
Lock() |
Initializes a new instance of the Lock class. |
Properties
IsHeldByCurrentThread |
Gets a value that indicates whether the lock is held by the current thread. |
Methods
Enter() |
Enters the lock, waiting if necessary until the lock can be entered. |
EnterScope() |
Enters the lock, waiting if necessary until the lock can be entered. |
Equals(Object) |
Determines whether the specified object is equal to the current object. (Inherited from Object) |
Exit() |
Exits the lock. |
GetHashCode() |
Serves as the default hash function. (Inherited from Object) |
GetType() |
Gets the Type of the current instance. (Inherited from Object) |
MemberwiseClone() |
Creates a shallow copy of the current Object. (Inherited from Object) |
ToString() |
Returns a string that represents the current object. (Inherited from Object) |
TryEnter() |
Tries to enter the lock without waiting. |
TryEnter(Int32) |
Tries to enter the lock, waiting if necessary for the specified number of milliseconds until the lock can be entered. |
TryEnter(TimeSpan) |
Tries to enter the lock, waiting if necessary until the lock can be entered or until the specified timeout expires. |