The instance passed to the lock
statement should be a dedicated private field.
Why is this an issue?
If the instance representing an exclusively acquired lock is publicly accessible, another thread in another part of the program could accidentally attempt to acquire the same lock. This increases the likelihood of deadlocks.
For example, a string should never be used for locking. When a string is interned by the runtime, it can be shared by multiple threads, breaking the
locking mechanism.
Instead, a dedicated private Lock object
instance (or object instance, for frameworks before .Net 9) should be used for locking. This minimizes access to the lock instance and
therefore prevents accidential lock sharing.
The following objects are considered potentially prone to accidental lock sharing:
- a reference to this: if the instance is publicly accessibly, the lock might be shared
- a Type object: if the type class is publicly accessibly, the lock might be shared
- a string literal or instance: if any other part of the program uses the same string, the lock is shared because of interning
How to fix it
Code examples
Noncompliant code example
void MyLockingMethod()
{
lock (this) // Noncompliant
{
// ...
}
}
Compliant solution
#if NET9_0_OR_GREATER
private readonly Lock lockObj = new();
#else
private readonly object lockObj = new();
#endif
void MyLockingMethod()
{
lock (lockObj)
{
// ...
}
}
Resources
Documentation
- Wikipedia - Thread
- Wikipedia - Locking
- Wikipedia - Deadlock
- Wikipedia - Interning
- Microsoft Learn - String interning by the runtime
- Microsoft Learn - Managed Threading Best Practices
- Microsoft Learn - The lock statement - ensure exclusive access to a shared resource